Embed the Genuin Web SDK on your website

Render your brand, community, and group feeds on your own pages with Web SDK 2.0.6, from one script tag to several embeds, sign-in, page context, and events.

The Genuin Web SDK is a script that turns a <div> on your page into a video embed. You configure the embed in Brand Control Center, which feed it shows and how it's laid out, and the SDK fetches that configuration by its embed ID and renders it. Saving a change in Brand Control Center updates every page that shows the embed at its next load.

This page covers embeds, where you pick the feed once. A placement chooses its videos at load time from the page a visitor is on; see Add a Genuin placement to your website. Both use the same script and the same init call.

What the SDK renders

An embed combines a feed source with a style, both set in Brand Control Center under Grow > On Site > Embed.

PartChoicesWhat visitors see
Feed sourceBrand Feed, Community Feed, Group FeedEverything published across your brand, or the communities or groups you pick
StyleStandard Wall, Feed, CarouselA grid of video tiles with navigation arrows, a vertical feed with a headline and button, or a horizontal row to swipe through
Expand viewOn or off per embedTapping a tile opens the full-screen player with comments, reactions, and sharing over your page
The three embed styles the SDK renders, chosen in the embed builder.

The SDK renders inside a Shadow DOM, so its styles never leak into your page and your CSS never reaches the player. It shows a skeleton at once, loads the player when the container comes within 200 px of the viewport, and sets the container's height to fit the content.

Requirements

RequirementDetail
BrowserES2020 JavaScript with dynamic import(), Shadow DOM, and IntersectionObserver. Genuin tests Chrome 80, Firefox 75, Safari 13, and Edge 80 and later.
HTTPSEvery SDK asset and API endpoint is served over HTTPS only. Serve the host page over HTTPS as well.
Content Security PolicyIf your page sets one, allow script-src and style-src for https://media.begenuin.com, connect-src for https://api.begenuin.com, https://media.begenuin.com, and https://rudderstack.begenuin.com, img-src and media-src for https://media.begenuin.com, style-src for https://fonts.googleapis.com, font-src for https://fonts.gstatic.com, and script-src for https://cdn.rudderlabs.com and https://cdn.jsdelivr.net. Brands that run ads add their ad vendors' hosts.
ContainerA block element with a non-zero width and height. The SDK treats a container with zero width or height as a hidden expand-only host and renders nothing inline.
CredentialsAn embed ID and your brand's API key, both from Brand Control Center. The key is a browser key and ships in your page source.
One brand per pageEvery container on a page must use embeds of the same brand. Sign-in uses the first embed's brand for the whole page.

Step 1: Copy the embed ID and API key

  1. In Brand Control Center, go to Grow > On Site and click Embed.
  2. On the embed's card, click the ⋯ menu and choose Copy Embed ID.
Copy Embed ID puts the id on the clipboard; the same menu edits or deletes the embed.
  1. Open the embed and click View Embed Code. The Web tab shows your API key in the generated init call. Copy the key from there.

To create the embed first, see Embed your community on your website.

Step 2: Add the container and the script

Add a container where the embed goes, then load the SDK from the versioned URL. The container needs an id of gen-sdk, an id that starts with gen-sdk-, or the class gen-sdk-class.

index.html
html
<div id="gen-sdk" class="gen-sdk-class" style="width: 100%; height: 600px;"></div>
<script src="https://media.begenuin.com/sdk/2.0.6/gen_sdk.min.js"></script>

The script is a 6 KB loader. It imports the SDK bundle and its stylesheet from the same /sdk/2.0.6/ directory and queues any init call you make before the bundle arrives.

Caution: Pin the version in the URL. The unversioned https://media.begenuin.com/sdk/gen_sdk.min.js serves the 1.2 line, which has a different API, and a floating URL changes behaviour without a deploy on your side.

Step 3: Initialize the embed

Call window.genuin.init once, after the script tag. You can call it before the bundle has loaded; the loader runs it when ready.

index.html
html
<script>
  window.genuin.init({
    embed_id: "{{EMBED_ID}}",
    api_key: "<<YOUR_API_KEY>>",
  });
</script>

The SDK finds every container on the page, fetches your brand with the API key, fetches the embed, and renders it. A container's data-* attributes override the matching init value, which is how one init call serves several embeds.

Note: init scans the DOM when it runs. In a framework, call it after the container has rendered; the SDK skips containers it has already initialized, so calling it again is safe.

Step 4: Show several embeds on one page

Give each container a unique id, put its embed ID on the element, and call init once. api_key in init is the fallback for containers without their own data-api-key.

Several embeds
html
<div id="gen-sdk-1" class="gen-sdk-class" data-embed-id="{{EMBED_ID_1}}"
     style="width: 100%; height: 600px;"></div>
<div id="gen-sdk-2" class="gen-sdk-class" data-embed-id="{{EMBED_ID_2}}"
     style="width: 100%; height: 400px;"></div>
<script src="https://media.begenuin.com/sdk/2.0.6/gen_sdk.min.js"></script>
<script>
  window.genuin.init({ api_key: "<<YOUR_API_KEY>>" });
</script>

Two containers with the same id log [Genuin SDK Warning]: Found 2 elements with the same ID and only the first initializes.

Step 5: Sign viewers in (Optional)

Visitors can watch without an account. To let them react, comment, and follow as themselves, pass an auto-login token that your server issued for the signed-in user. The SDK exchanges it for a Genuin session, creating the account on first use from params.

Sign in at load
js
window.genuin.init({
  embed_id: "{{EMBED_ID}}",
  api_key: "<<YOUR_API_KEY>>",
  token: "{{AUTO_LOGIN_TOKEN}}",
  params: { name: "Ada Lovelace", email: "ada@example.com", nickname: "ada" },
});

When the visitor signs in later, call update with the token; it signs them into every embed on the page. Call logout when they sign out of your site.

Sign in later
js
window.genuin.update({ container_id: "gen-sdk", token: "{{AUTO_LOGIN_TOKEN}}", user_params: {} });
window.genuin.logout();

To run your own login screen when a signed-out visitor taps an action, define window.genuinAuth before init. The SDK calls it instead of showing its own sign-in, with the action the visitor attempted and returnQueryParams to restore it after login.

Your login screen
js
window.genuinAuth = ({ action, returnQueryParams }) => {
  // Open your login flow, then hand the token to the SDK:
  // window.genuin.update({ container_id: "gen-sdk", token: "{{AUTO_LOGIN_TOKEN}}", user_params: {} });
};

An invalid or expired token leaves the visitor signed out; the SDK logs a warning and renders the embed anyway. How tokens are issued is covered in How Auto Login works and Choose how members sign in to the Genuin SDK.

Step 6: Pass page context (Optional)

An embed with no fixed community or group ranks its videos toward the page_context you send. Pass it in contextual_params, and change it with update when a single-page app changes route; the embed reloads with the merged context.

Page context
js
window.genuin.init({
  embed_id: "{{EMBED_ID}}",
  api_key: "<<YOUR_API_KEY>>",
  contextual_params: {
    page_context: "electric SUVs, charging, range",
    geo: { lat: 37.7749, long: -122.4194 },
  },
});
// Later, on a route change:
window.genuin.update({ container_id: "gen-sdk", contextual_params: { page_context: "hybrid sedans" } });

On a container, the same values are data-page-context, data-lat, and data-long. The full list of signals and how they rank the feed are in Deliver contextual feeds with page, user, and location context and How contextual feeds choose videos.

Step 7: Open a specific video (Optional)

To land a visitor on one video, pass its slug. By default this opens the expand view on load; set data-expand-on-load="false" to play it inline instead.

Open a video
html
<div id="gen-sdk" class="gen-sdk-class"
     data-embed-id="{{EMBED_ID}}" data-api-key="<<YOUR_API_KEY>>"
     data-start-video-slug="{{VIDEO_SLUG}}"
     style="width: 100%; height: 600px;"></div>

Add data-action="comment" to open the comment box as well, or data-comment-id to focus one comment. From code, window.genuin.expand("gen-sdk") and window.genuin.collapse("gen-sdk") open and close the expand view of a container.

Use the SDK in a framework

The SDK has no npm package; every framework loads the same script. The pattern is the same everywhere: render the container, load the script once, and call init after it loads.

React

Add a type declaration once so window.genuin compiles.

genuin.d.ts
ts
interface Window {
  genuin?: {
    init: (config: Record<string, unknown>) => Promise<void>;
    update: (config: Record<string, unknown>) => Promise<void>;
    on: (event: string, listener: (e: { type: string; payload: unknown }) => void) => Promise<() => void>;
    logout: () => Promise<void>;
  };
}

Then load the script in an effect. The guard keeps React strict mode and re-mounts from adding it twice.

GenuinEmbed.tsx
tsx
import { useEffect } from "react";

const SDK_URL = "https://media.begenuin.com/sdk/2.0.6/gen_sdk.min.js";

export function GenuinEmbed({ embedId }: { embedId: string }) {
  useEffect(() => {
    if (document.querySelector(`script[src="${SDK_URL}"]`)) {
      window.genuin?.init({});
      return;
    }
    const script = document.createElement("script");
    script.src = SDK_URL;
    script.async = true;
    script.onload = () => window.genuin?.init({});
    document.body.appendChild(script);
  }, []);

  return (
    <div id="gen-sdk" className="gen-sdk-class" data-embed-id={embedId}
         data-api-key="<<YOUR_API_KEY>>" style={{ width: "100%", height: 600 }} />
  );
}

Next.js

In the App Router, render the container and the script from a client component with next/script. afterInteractive loads the SDK after hydration, and onLoad runs init once the loader is on the page.

app/components/genuin-embed.tsx
tsx
"use client";
import Script from "next/script";

export function GenuinEmbed({ embedId }: { embedId: string }) {
  return (
    <>
      <div id="gen-sdk" className="gen-sdk-class" data-embed-id={embedId}
           data-api-key="<<YOUR_API_KEY>>" style={{ width: "100%", height: 600 }} />
      <Script
        src="https://media.begenuin.com/sdk/2.0.6/gen_sdk.min.js"
        strategy="afterInteractive"
        onLoad={() => window.genuin?.init({})}
      />
    </>
  );
}

next/script loads a given src once per session, so onLoad doesn't fire again on client-side navigation. On pages reached that way, call window.genuin?.init({}) from a useEffect as well; already-initialized containers are skipped.

Angular

Inject the script in ngAfterViewInit, once the container exists. The component below is standalone and works in Angular 16 and later.

genuin-embed.component.ts
ts
import { AfterViewInit, Component, Input } from "@angular/core";

@Component({
  selector: "genuin-embed",
  standalone: true,
  template: `<div id="gen-sdk" class="gen-sdk-class" [attr.data-embed-id]="embedId"
    data-api-key="<<YOUR_API_KEY>>" style="width: 100%; height: 600px"></div>`,
})
export class GenuinEmbedComponent implements AfterViewInit {
  @Input({ required: true }) embedId!: string;

  ngAfterViewInit(): void {
    const src = "https://media.begenuin.com/sdk/2.0.6/gen_sdk.min.js";
    const genuin = () => (window as any).genuin;
    if (document.querySelector(`script[src="${src}"]`)) { genuin()?.init({}); return; }
    const script = document.createElement("script");
    script.src = src;
    script.async = true;
    script.onload = () => genuin()?.init({});
    document.body.appendChild(script);
  }
}

Configuration reference

init options

Pass these to window.genuin.init. Where a data attribute exists, setting it on a container overrides the init value for that container.

ParameterTypeRequiredDefaultDescription
api_keystringYesnoneYour brand's API key. Data attribute: data-api-key.
embed_idstringYes, unless a placement is setnoneThe embed to render. Data attribute: data-embed-id.
placement_idstringNononeWith style_id, renders a placement instead of an embed. See Add a Genuin placement to your website. Data attribute: data-placement-id.
style_idstringNononeThe placement style. Data attribute: data-style-id.
tokenstringNononeAuto-login token for the current visitor. Empty, "null", and "undefined" are ignored. Data attribute: data-token.
paramsobjectNononeProfile for a new account created from token: name, email, mobile, nickname, profileImage (URL), brandUserIdentity.
contextual_paramsobjectNononePage and viewer context: page_context, previous_page_context, user_context, url, geo (lat, long, radius_limit), place, time, user_segments, user_interests, brands_ids, community_ids, loop_ids, posted_by_user_ids. Data attributes: data-page-context, data-previous-page-context, data-user-context, data-url, data-lat, data-long, data-geo, data-place, data-time, data-user-segments, data-user-interests, data-brands-ids, data-community-ids, data-loop-ids, data-posted-by-user-ids; objects and arrays as JSON strings.
configurationobjectNononePlacement only. Overrides the style's style_title, style_subtitle, and sections.
start_video_slugstringNononeVideo to open on load. Sets expand_on_load to true unless you set it to false. Data attribute: data-start-video-slug.
actionstringNononeInteraction to perform on the start video: spark, comment-spark, repost, comment, report, join-community, join-group, subscribe-group, become-a-creator, octo. Data attribute: data-action.
comment_idstringNononeComment to focus when the start video opens. Data attribute: data-comment-id.
auth_infoobjectNononesignInUrl and signUpUrl, each a string or a function returning one. Sign-in prompts send the visitor there instead of showing the SDK's own flow.
error_handlerfunctionNononeCalled with { isError, isNoContent } when an embed fails to load or its feed is empty.
theme"light" or "dark"No"light"Colour theme of the player. Data attribute: data-theme.
useShadowDOMbooleanNotrueSet false to render into the page's DOM; the SDK's styles then share your cascade.
allow_gesture_scrollbooleanNotrueSet false to turn off swipe and drag between tiles. Data attribute: data-allow-gesture-scroll.
video_idsstringNononeComma-separated video ids that replace the feed. Data attribute: data-video-ids.
initial_video_idsstringNononeComma-separated video ids to show first, ahead of the feed. Data attribute: data-initial-video-ids.
targetingobjectNononeAd and sponsorship targeting: keywords (string or array), location, page_url, and an open key_value map of up to 50 entries. Keywords and location are read from the page's <meta name="keywords"> and geo-IP when omitted.
sponsorship_idstring[]NononeOverrides the sponsorship attached to the embed. An empty array counts as absent.
expand_on_loadbooleanNofalseData attribute only: data-expand-on-load="true" opens the expand view as soon as the embed loads.
embed_style"expand_only"NononeData attribute only: data-embed-style="expand_only" renders no inline player and serves the expand view alone.
brand_context, website_type, parent_instance_id, live—NononePartner and internal options for publisher integrations, preview mode, and nested SDK instances. Don't set them unless Genuin asks you to.

contextualParams, authInfo, and errorHandler still work as aliases but are deprecated; use the snake-case names.

update options

Pass these to window.genuin.update after init. Calls made before the SDK is ready are queued.

ParameterTypeRequiredDefaultDescription
container_idstringYesnoneThe id of the container to update.
tokenstringNononeSigns the visitor into every embed on the page. The TypeScript type lists it as required; an empty string is ignored.
user_paramsobjectNononeSame keys as params. Listed as required by the type; pass {} when you have nothing to send.
contextual_paramsobjectNononeMerged into the container's current context, then the feed reloads.
targetingobjectNononeReplaces the container's targeting, so a field you leave out is cleared.
start_video_slugstringNononeOpens this video in the container's expand view. action and comment_id apply as in init.

Methods

MethodReturnsWhat it does
init(config)PromiseFinds containers and renders them. Safe to call before the bundle has loaded.
update(config)PromiseChanges a container's token, context, targeting, or start video.
on(event, listener)Promise of an unsubscribe functionSubscribes to one of the events below. The listener receives { type, payload, timestamp }.
off(event, listener)PromiseRemoves a listener.
emit(event, payload)PromiseSends a command to the player: player:play, player:pause, player:mute, player:unmute, or sdk:themeChange.
expand(containerId)PromiseOpens the container's expand view.
collapse(containerId)PromiseCloses it.
logout()PromiseClears the signed-in visitor from every embed.
destroy()voidUnmounts every embed and removes all listeners. Available once the bundle has loaded.
version, isLoaded(), isLoading()string, booleanThe loader's version and bundle state.

Events

Subscribe with on, which returns a function that unsubscribes. off(eventType, listener) removes a listener you kept a reference to. Names outside this list are rejected with a console warning.

Subscribe
js
window.genuin.on("onPlay", (event) => {
  console.log(event.type, event.payload.muted, event.payload.isInView);
});
EventPayloadFires when
onFeedLoadedvideoCount, hasNextPage, isSectioned, feedType, thumbnailUrl, videoUrlA feed page has loaded
onPlaymuted, isInView, isFocused, volume, autoplayA video starts playing
onPausemuted, isInView, isFocused, volumeA video pauses
onMuteChangemuted, volume, instanceIdThe visitor mutes or unmutes
onSwipedForward, onSwipedBackwardfromIndex, toIndex, timestampThe visitor moves to another video
onVideoClickedvideoIdA tile is clicked
onExpandViewChangedtrue or falseThe expand view opens or closes
onShareshareUrl, type, id, clipTitle, clipDescription, clipThumbnailUrlThe visitor shares a video
onVideoNotFoundslug, errorCodeA start_video_slug doesn't resolve
onAnalyticsTrackeventName, eventPayloadThe SDK records an analytics event, for forwarding to your own analytics
onFollowChanged, onCaughtOverlay, checkFollowingStatus, playIHeartContentvariesPublisher-partner integrations; unused in a standard embed

Troubleshooting

SymptomCauseFix
Nothing renders; the console shows Failed to fetch brand detailsThe API key is missing or wrong, or belongs to another environmentCopy the key from the Web tab of View Embed Code and pass it as api_key or data-api-key.
Console error Placement ID or Style ID is missing, and no embed ID providedThe container has no data-embed-id and init has no embed_id, or only one of placement_id and style_id was setAdd the embed ID, or both placement values.
[Genuin SDK Warning]: Found N elements with the same IDTwo containers share an idGive each container a unique id, such as gen-sdk-1 and gen-sdk-2.
No valid SDK elements found for initialization.init ran before the container existed, or the container lacks the gen-sdk id prefix and classRender the container first, then call init.
window.genuin is undefinedThe init script runs before the SDK script tag, or the script failed to loadPlace the script tag before the init call and check the URL in the Network tab.
The player shows Unable to load contentThe embed doesn't exist, the brand's web SDK is off, or a network error occurredCheck the embed ID in Brand Control Center and the failing request in the Network tab; error_handler receives isError: true.
The expand view opens but nothing renders inlineThe container had zero width or height when init ranGive the container a width and a height in CSS.
The visitor stays signed out after passing tokenThe auto-login request returned 401, or browser storage is blockedCheck that the token is current and issued for this brand. In a private window or inside a third-party iframe, the SDK keeps the session in memory only, so it ends with the page.
Scripts, styles, or requests are blockedYour Content Security Policy doesn't allow a Genuin hostAdd the hosts from the Requirements table.
SDK initialization is disabled via URL parameter.The page URL contains disableGenSdk=trueRemove the parameter.

Limitations

  • CDN only: There's no npm package. Load https://media.begenuin.com/sdk/2.0.6/gen_sdk.min.js and pin the version.
  • One brand per page: Sign-in resolves the brand from the first embed, so mixing brands on a page breaks authentication.
  • Containers need a size: A zero-sized or hidden container is treated as an expand-only host.
  • Shadow DOM: Your CSS doesn't style the player, and the player uses the Inter font loaded from Google Fonts. There's no font option in 2.0.6.
  • Fixed event list: on accepts only the events listed above. Container resizing is handled internally and isn't subscribable.
  • Context merges, targeting replaces: update merges contextual_params into the existing context but replaces targeting wholesale.
  • Key-value targeting caps: 50 entries, keys up to 128 characters, values up to 1,024 characters, keywords up to 100 of 256 characters each, page_url up to 2,048 characters. Larger values are dropped with a console warning.
  • Lazy rendering: Embeds render when they come within 200 px of the viewport, except when a start video or expand-on-load is set.

See also

TRUST AND COMPLIANCE

© 2026 Genuin Inc.

Genuin Footer