Skip to main content

JavaScript widget installation

Two things go on the page: the script and a container <div>. That is the whole client-side install. Everything else is prerequisites on your side and a token endpoint on your backend.

Prerequisites

Complete these before adding the script. The widget will load without them, but it will not be able to do anything for a logged-in user.

PrerequisiteDetail
Key exchangePublisher and Cheggout exchange public key certificates. Cheggout needs yours to verify your signed token requests; you need Cheggout's to verify signed responses.
HTTPSAll communication happens over HTTPS. This includes the pages hosting the widget.
Request signingRequests are signed using SHA256withRSA. This applies to the server-side token call your backend makes, not to anything running in the browser.
The script itselfCheggout provides the JavaScript to be integrated into the publisher page, along with your channelName.
A token endpointYour backend must be able to mint a user token. See User states and tokens.
Never sign in the browser

Your RSA private key stays on your servers. The widget takes a bearer token that your backend minted; it never sees a key and never constructs a signature. If you find yourself putting a private key into JavaScript, stop — see Security best practices.

Step 1 — Add the script

<script src="https://chegwidgetuat.z29.web.core.windows.net/cheggout-widget.iife.js?channelName=YOURCHANNEL"></script>

The channelName query parameter is not decorative: the widget reads it from its own script tag's src. There is no separate init() call and no configuration object. Get the query string wrong and the widget loads but cannot identify your channel.

Replace YOURCHANNEL with the channel identifier Cheggout issued you. It is matched case-sensitively and is the same value your backend sends as CHANNELID in the signed envelope.

This is a UAT host

TBD The URL above is the only published distribution point, and it is a UAT blob host. There is no production widget URL. Do not ship it to production traffic. Confirm the production URL with Cheggout before committing to a launch date. Tracked in Open items.

Where to put it

Place the tag where your template loads third-party scripts. Because the widget only acts when you call a trigger function, load order is not critical — but window.CheggoutRewards must exist before your first call, so either load it synchronously in <head>, or guard your calls:

if (window.CheggoutRewards) {
window.CheggoutRewards.bannerTriggerEvent(/* ... */);
}

Step 2 — Add the container

Reward banners are injected into a container with an exact id:

<div id="cheggout-banner-container" class="my-8 min-h-[90px] w-full"></div>
AttributeRequiredWhy
id="cheggout-banner-container"Yes, exactlyThe widget queries for this id. Any other id, and the banner has nowhere to render.
class="my-8 min-h-[90px] w-full"No, but recommendedTailwind utilities giving vertical margin, a minimum height of 90px, and full width. Reproduce the same intent with your own CSS if you do not use Tailwind.

The min-height matters more than it looks. Without a reserved height, the container is zero pixels tall until the banner renders, and injecting the banner shifts your page content down — a layout shift the user sees and your Core Web Vitals record.

Place the container where the banner should appear: at the end of article body copy for a reading-milestone reward, or near the confirmation message on a transaction page.

Step 3 — Trigger it

The widget does not watch your page. Nothing renders until you call a trigger function.

window.CheggoutRewards.bannerTriggerEvent(
virtualId, // "pub_8f14e45fceea167a", or "guest"
authToken, // bearer token from your backend
"article_read", // event type
"web", // device type
{} // additionalParams
);

Every function, its parameters and when to call it are in Trigger events.

TypeScript

If your site is TypeScript, declare the global so calls type-check. The declaration circulated with the integration material covers the legacy function:

cheggout.d.ts
declare global {
interface Window {
CheggoutRewards?: {
fetchScratchCard: (category: string, virtualId: string, trackerEvent: any) => void;
};
}
}

export {};

For new integrations you will also want the current functions. Extend the same declaration:

cheggout.d.ts
declare global {
interface Window {
CheggoutRewards?: {
bannerTriggerEvent: (
virtualId: string,
authToken: string,
eventType: string,
deviceType: string,
additionalParams?: Record<string, unknown>
) => void;
checkPendingRewardEvent: (
virtualId: string,
authToken: string,
eventType?: string,
additionalParams?: Record<string, unknown>
) => void;
/** @deprecated Legacy. Use bannerTriggerEvent for new integrations. */
fetchScratchCard: (category: string, virtualId: string, trackerEvent: any) => void;
};
}
}

export {};

The optional ? on CheggoutRewards is deliberate — the script may not have loaded when your code runs, and the type should force you to handle that.

TBD No official type definitions package is published. The declarations above are written from the documented signatures; confirm them against the build you receive.

A complete page

<!-- In your template head or script block -->
<script src="https://chegwidgetuat.z29.web.core.windows.net/cheggout-widget.iife.js?channelName=YOURCHANNEL"></script>

<article>
<!-- your content -->

<!-- Where the reward banner appears -->
<div id="cheggout-banner-container" class="my-8 min-h-[90px] w-full"></div>
</article>

<script>
// Your own milestone logic decides when this fires.
function onArticleFinished(articleId) {
if (localStorage.getItem('cheggout_banner_clicked_' + articleId) === 'true') {
return; // already rewarded for this article
}

const virtualId = sessionStorage.getItem('vid') || 'guest';
const authToken = window.myApp.cheggoutToken || ''; // minted server-side

window.CheggoutRewards &&
window.CheggoutRewards.bannerTriggerEvent(
virtualId, authToken, 'article_read', 'web', {}
);
}
</script>

Caveats

There is no separate stylesheet

The CSS link is not required

TBD An earlier integration email referenced a separate cheggout-widget.css stylesheet <link>. Styles are bundled inside the script. Treat a separate CSS link as legacy — do not add it. If a build you receive genuinely needs one, Cheggout will say so at handover; confirm rather than guessing.

The widget owns its own visuals

You place the container and control its outer box — margin, width, position in the flow. You do not restyle the banner or the overlay. If you need visual control over the card itself, the widget is the wrong surface; use the headless API.

One container, one banner region

Only one #cheggout-banner-container should exist on a page. Duplicate ids are invalid HTML, and the widget will find whichever the browser returns first.

Demo

A working sample application is available at:

https://cheggoutsampleapp.z29.web.core.windows.net/news

Compare its DOM against yours when a banner fails to appear — a missing container id is by far the most common cause.

Next