> ## Documentation Index
> Fetch the complete documentation index at: https://docs.supahub.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed on Website

> Embed the feedback, roadmap or changelog public view natively on your website.

You can easily embed the feedback, roadmap, or changelog public view natively on your website with Supahub.

## Installation

To embed Supahub on your website, copy & paste the provided code snippet:

<CodeGroup>
  ```javascript HTML theme={null}
  <!-- Embed Supahub -->
  <div data-supahub-embed></div>

  <script id="supahub" type="text/javascript">
    !(function (s, u, p, a) {
      function supahub() {
        var g = u.createElement(p),
          h = u.getElementsByTagName(p)[0];
        (g.id = a),
          (g.src = "https://widget.supahub.com/sdk.js"),
          h.parentNode.insertBefore(g, h);
        g.onload = function () {
          window.SupahubWidget("embed", {
            workspaceName: "workspace-name", // Required: Copy your workspace name from 'workspace-name.supahub.com'
            initialPage: "Board", // Optional: Options ("Board" | "Roadmap" | "Changelog")
            hideLogo: false, // Optional: Set to true to hide logo from Navbar
            hideNav: false, // Optional: Set to true to hide Navbar
          });
        };
      }
      "function" != typeof s.SupahubWidget &&
        (s.SupahubWidget = function () {
          (s.SupahubWidget.q = s.SupahubWidget.q || []).push(arguments);
        }),
        "complete" === u.readyState || "interactive" === u.readyState
          ? supahub()
          : s.addEventListener("DOMContentLoaded", supahub);
    })(window, document, "script", "supahub-sdk");
  </script>
  ```

  ```javascript Next.js theme={null}
  "use client"; // NextJS 13 requires this. Remove if you are using NextJS 12 or lower.

  import Script from "next/script";

  const SupahubEmbed = () => {
    return (
      <>
        <Script id="supahub" strategy="afterInteractive" type="text/javascript">
          {`!(function (s, u, p, a) {
            function supahub() {var g=u.createElement(p),h=u.getElementsByTagName(p)[0];(g.id=a),(g.src="https://widget.supahub.com/sdk.js"),h.parentNode.insertBefore(g, h);
              g.onload = function () {
                window.SupahubWidget("embed", {
                    workspaceName: "workspace-name", // Required: Copy your workspace name from 'workspace-name.supahub.com'
                    initialPage: "Board", // Optional: Options ("Board" | "Roadmap" | "Changelog")
                    hideLogo: false, // Optional: Set to true to hide logo from Navbar
                    hideNav: false, // Optional: Set to true to hide Navbar
                });
              }};
            "function"!=typeof s.SupahubWidget&&(s.SupahubWidget=function(){(s.SupahubWidget.q=s.SupahubWidget.q||[]).push(arguments);}),"complete"===u.readyState||"interactive"===u.readyState?supahub():s.addEventListener("DOMContentLoaded", supahub);
            })(window, document, "script", "supahub-sdk");`}
        </Script>

        {/* Embed Supahub */}
        <div data-supahub-embed></div>
      </>
    );
  };

  export default SupahubEmbed;
  ```

  ```javascript Vue.js theme={null}
  <script lang="ts" setup>
  import { onMounted } from "vue";

  onMounted(() => {
    if (document.getElementById("supahub-sdk")) {
      return;
    }

    const script = document.createElement("script");
    script.id = "supahub-sdk";
    script.src = "https://widget.supahub.com/sdk.js";
    script.async = true;
    script.onload = () => {
      const win: any = window;
      win.SupahubWidget("embed", {
        workspaceName: "workspace-name", // Required: Copy your workspace name from 'workspace-name.supahub.com'
        initialPage: "Board", // Optional: Options ("Board" | "Roadmap" | "Changelog")
        hideLogo: false, // Optional: Set to true to hide logo from Navbar
        hideNav: false, // Optional: Set to true to hide Navbar
      });
    };

    document.head.appendChild(script);
  });
  </script>

  <template>
    <h1>This is a component</h1>
    <!-- Embed Supahub -->
    <div data-supahub-embed></div>
  </template>

  <style>
  ...
  </style>
  ```
</CodeGroup>

## Usage of Embed

To use embed in your website, add the `data-supahub-embed` attribute to a div element:

```javascript theme={null}
// Embed Supahub
<div data-supahub-embed></div>
```

## Single Sign-On with Embedding

The embed supports authenticating your users via SSO.

Here’s what you need to do:

1. Log in to acquire your private key from SSO settings. Ensure that you store this key securely on your server and prevent unauthorized access.

2. When a user visits the embed, send a request to your server to generate a JWT token.

3. Generate a token on your server with customer data using the provided snippet.

4. Pass the generated JWT token to the Supahub embed for authentication.

<Steps>
  <Step title="Install JWT packages">
    Install the required packages for JWT token generation on your server.

    <CodeGroup>
      ```javascript Node.js theme={null}
      npm install --save jsonwebtoken
      ```

      ```python Python theme={null}
      pip install pyjwt
      ```

      ```javascript C# theme={null}
      // Instructions here
      https://www.nuget.org/packages/System.IdentityModel.Tokens.Jwt/
      ```

      ```java Java theme={null}
      // Instructions here
      https://github.com/jwtk/jjwt#install
      ```

      ```go Go theme={null}
      go get github.com/golang-jwt/jwt
      ```

      ```php PHP theme={null}
      composer require firebase/php-jwt
      ```
    </CodeGroup>
  </Step>

  <Step title="Generate the JWT token">
    Copy and use the “Private Key” from SSO settings to generate a JWT token on your server.

    <CodeGroup>
      ```javascript Node.js theme={null}
      var jwt = require("jsonwebtoken");
      const SSO_KEY = "YOUR_PRIVATE_SSO_KEY";

      function generateJWTToken(user) {
          var userData = {
              email: user.email, // Required
              name: user.name, // Required
              id: user.id, // Required
          };

          // The userData object can include any additional details you wish to provide about a user to Supahub. Ensure to follow the same format shown in the Supahub.identify method, as outlined at https://docs.supahub.com/identify/user

          return jwt.sign(userData, SSO_KEY, {
              algorithm: "HS256",
          });
      }
      ```

      ```python Python theme={null}
      import jwt
      from datetime import datetime, timedelta

      SSO_KEY = "YOUR_PRIVATE_SSO_KEY"

      def generate_JWT_token(user):
          userData = {
              'email': user['email'], # Required
              'name': user['name'], # Required
              'id': user['id'], # Required
          }

          # The userData object can include any additional details you wish to provide about a user to Supahub. Ensure to follow the same format shown in the Supahub.identify method, as outlined at https://docs.supahub.com/identify/user

          return jwt.encode(userData, SSO_KEY, algorithm='HS256')
      ```

      ```javascript C# theme={null}
      using System;
      using System.IdentityModel.Tokens.Jwt;
      using System.Security.Claims;
      using Microsoft.IdentityModel.Tokens;

      public string GenerateJwtToken(User user)
      {
          var claims = new[]
          {
              new Claim("email", user.email), // Required
              new Claim("name", user.name), // Required
              new Claim("id", user.id), // Required
          };

          // The userData object can include any additional details you wish to provide about a user to Supahub. Ensure to follow the same format shown in the Supahub.identify method, as outlined at https://docs.supahub.com/identify/user

          var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_PRIVATE_SSO_KEY"));
          var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

          var token = new JwtSecurityToken(
              claims: claims,
              signingCredentials: creds);

          return new JwtSecurityTokenHandler().WriteToken(token);
      }
      ```

      ```java Java theme={null}
      import io.jsonwebtoken.Jwts;
      import io.jsonwebtoken.SignatureAlgorithm;

      String SSO_KEY = "YOUR_PRIVATE_SSO_KEY";

      public String generateJwtToken(User user) {
          Map<String, Object> claims = new HashMap<>();
          claims.put("email", user.getEmail()); // Required
          claims.put("name", user.getName()); // Required
          claims.put("id", user.getId()); // Required

          // The userData object can include any additional details you wish to provide about a user to Supahub. Ensure to follow the same format shown in the Supahub.identify method, as outlined at https://docs.supahub.com/identify/user

          return Jwts.builder()
              .setClaims(claims)
              .signWith(SignatureAlgorithm.HS256, SSO_KEY)
              .compact();
      }
      ```

      ```go Go theme={null}
      import (
          "github.com/golang-jwt/jwt",
      )

      var SSO_KEY = []byte("YOUR_PRIVATE_SSO_KEY")

      func GenerateJwtToken(user User) (string, error) {
          token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
              "email": user.email, // Required
              "name": user.name, // Required
              "id": user.id, // Required
          })

          // The userData object can include any additional details you wish to provide about a user to Supahub. Ensure to follow the same format shown in the Supahub.identify method, as outlined at https://docs.supahub.com/identify/user

          return token.SignedString([]byte(PrivateKey));
      }
      ```

      ```php PHP theme={null}
      use FirebaseJWTJWT;

      $SSO_KEY = "YOUR_PRIVATE_SSO_KEY";

      function generateJwtToken($user) {
          $payload = array(
              "email" => $user['email'], // Required
              "name" => $user['name'], // Required
              "id" => $user['id'], // Required
          );

          // The userData object can include any additional details you wish to provide about a user to Supahub. Ensure to follow the same format shown in the Supahub.identify method, as outlined at https://docs.supahub.com/identify/user

          return JWT::encode($payload, $SSO_KEY);
      }
      ```
    </CodeGroup>

    <Warning>
      Private Key should be kept secure and not to be shared. Add it in your .env
      file.
    </Warning>

    <Note>
      To enhance security measures, Single Sign-On (SSO) tokens are restricted from authenticating users with administrative privileges within any Supahub workspace. Instead, these users will need to log in using the dedicated portal at workspace.supahub.com
    </Note>
  </Step>

  <Step title="Pass the token back to your app and into our embed">
    The token will be used for user authentication.

    <CodeGroup>
      ```javascript HTML theme={null}
      <script id="supahub" type="text/javascript">
        !(function (s, u, p, a) {
          function supahub() {
            var g = u.createElement(p),
              h = u.getElementsByTagName(p)[0];
            (g.id = a),
              (g.src = "https://widget.supahub.com/sdk.js"),
              h.parentNode.insertBefore(g, h);
            g.onload = function () {
              window.SupahubWidget("embed", {
                workspaceName: "workspace-name", // Required: Copy your workspace name from 'workspace-name.supahub.com'
                initialPage: "Board", // Optional: Options ("Board" | "Roadmap" | "Changelog")
                hideLogo: false, // Optional: Set to true to hide logo from Navbar
                hideNav: false, // Optional: Set to true to hide Navbar
                jwtToken: "Generated_JWT_Token", // Optional: Replace with the token generated from your server
              });
            };
          }
          "function" != typeof s.SupahubWidget &&
            (s.SupahubWidget = function () {
              (s.SupahubWidget.q = s.SupahubWidget.q || []).push(arguments);
            }),
            "complete" === u.readyState || "interactive" === u.readyState
              ? supahub()
              : s.addEventListener("DOMContentLoaded", supahub);
        })(window, document, "script", "supahub-sdk");
      </script>
      ```

      ```javascript Next.js theme={null}
      "use client"; // NextJS 13 requires this. Remove if you are using NextJS 12 or lower.

      import Script from "next/script";

      const AllInOneWidget = () => {
        return (
          <>
            <Script id="supahub" strategy="afterInteractive" type="text/javascript">
              {`!(function (s, u, p, a) {
                function supahub() {var g=u.createElement(p),h=u.getElementsByTagName(p)[0];(g.id=a),(g.src="https://widget.supahub.com/sdk.js"),h.parentNode.insertBefore(g, h);
                  g.onload = function () {
                    window.SupahubWidget("embed", {
                      workspaceName: "workspace-name", // Required: Copy your workspace name from 'workspace-name.supahub.com'
                      initialPage: "Board", // Optional: Options ("Board" | "Roadmap" | "Changelog")
                      hideLogo: false, // Optional: Set to true to hide logo from Navbar
                      hideNav: false, // Optional: Set to true to hide Navbar
                      jwtToken: "Generated_JWT_Token", // Optional: Replace with the token generated from your server
                    });
                  }};
                "function"!=typeof s.SupahubWidget&&(s.SupahubWidget=function(){(s.SupahubWidget.q=s.SupahubWidget.q||[]).push(arguments);}),"complete"===u.readyState||"interactive"===u.readyState?supahub():s.addEventListener("DOMContentLoaded", supahub);
                })(window, document, "script", "supahub-sdk");`}
            </Script>
          </>
        );
      };

      export default AllInOneWidget;
      ```

      ```javascript Vue.js theme={null}
      <script lang="ts" setup>
      import { onMounted } from "vue";

      onMounted(() => {
        if (document.getElementById("supahub-sdk")) {
          return;
        }

        const script = document.createElement("script");
        script.id = "supahub-sdk";
        script.src = "https://widget.supahub.com/sdk.js";
        script.async = true;
        script.onload = () => {
          const win: any = window;
          win.SupahubWidget("embed", {
            workspaceName: "workspace-name", // Required: Copy your workspace name from 'workspace-name.supahub.com'
            initialPage: "Board", // Optional: Options ("Board" | "Roadmap" | "Changelog")
            hideLogo: false, // Optional: Set to true to hide logo from Navbar
            hideNav: false, // Optional: Set to true to hide Navbar
            jwtToken: "Generated_JWT_Token", // Optional: Replace with the token generated from your server
          });
        };

        document.head.appendChild(script);
      });
      </script>

      <template>
        <h1>This is a component</h1>
        <!-- Embed Supahub -->
        <div data-supahub-embed></div>
      </template>

      <style>
      ...
      </style>
      ```
    </CodeGroup>
  </Step>
</Steps>
