Guest & logged-in users
Web publishers have a problem mobile apps do not: most visitors are anonymous. The widget handles this with a guest state, and a defined path for converting a guest into a signed-in customer who keeps the reward they earned.
The two states
| Guest | Logged in | |
|---|---|---|
virtualId | "guest" | Your identifier for the customer |
authToken | Not required | Required |
| Reward | Earned, held pending | Claimable |
The guest flow
When virtualId is "guest", the customer is treated as non-logged-in.
The documented behaviour:
- From the trigger event, run the banner flow as normal.
- The customer should be redirected to the publisher login page to claim.
authTokenis not required while they are a guest.
After they successfully sign in:
authTokenis required — obtain it from the token API.- Re-trigger the flow, passing the updated
virtualId. - Include all required parameters:
virtualId,authToken,eventType,deviceType,additionalParams.
Without it, the customer signs in and the reward they were promised does not appear. This is the single most common failure in a web widget integration — the login redirect is implemented, the return path is not.
Implementing the return
Your login flow needs to know it was triggered by a reward claim, and re-trigger on return.
// Before redirecting to login, remember why
sessionStorage.setItem('cheggout_pending_claim', 'true');
window.location.href = '/login?return=' + encodeURIComponent(window.location.pathname);
// After login completes, on return
if (sessionStorage.getItem('cheggout_pending_claim') === 'true') {
sessionStorage.removeItem('cheggout_pending_claim');
const virtualId = getYourUserId();
const authToken = await fetchCheggoutToken(); // from your backend
window.CheggoutRewards.bannerTriggerEvent(virtualId, authToken, 'article_read', 'web', {});
}
Also call checkPendingRewardEvent on your landing
and home pages immediately after login. It catches customers who signed in through a different route
and still have something unclaimed.
The token API
The authToken is minted from your server, never in the browser — minting requires your private
key.
POST /api/GetAuthToken
Authenticated with the signed envelope.
{
"virtualId": "pub_8f14e45fceea167a",
"channelName": "YOURCHANNEL"
}
{
"token": "REPLACE_WITH_TOKEN",
"expireDate": "REPLACE_WITH_EXPIRY"
}
The token is used as the bearer credential for the reward APIs the widget calls on the customer's behalf.
Validity
The token is valid for one hour. After it expires, obtain a new one by calling the same token API from the server before making further requests.
That one-hour figure is documented for the widget token specifically. Other token lifetimes vary by channel — see Tokens.
Minting requires your RSA private key. Expose a small endpoint on your own backend that your page calls to obtain a token for the current session — the key stays server-side, and the browser only ever sees the short-lived result.
// Your own endpoint, not Cheggout's
async function fetchCheggoutToken() {
const res = await fetch('/api/cheggout/token', {credentials: 'include'});
const {token} = await res.json();
return token;
}
Your endpoint authenticates the customer with your own session, resolves their virtualId, and mints
the Cheggout token server-side. Cache it per user for its lifetime rather than minting per page view.
Host
TBD GetAuthToken is published against more than one host family across
Cheggout's documents. Confirm the host that applies to your channel during onboarding rather than
copying one from another integration. See
Environments and
GetAuthToken.
Guest identification
The guest state uses the literal value "guest" as virtualId.
Send exactly "guest" for anonymous visitors. Values such as guest_12345 are not the documented
guest marker, and how the platform classifies them is unspecified. If you need to distinguish
anonymous sessions on your own side, track that in your analytics rather than in virtualId.
Privacy on the web
Browser storage is readable by every script on the page, and the widget keeps interaction state there. Keep your third-party script surface tight on pages where the widget runs, and never place a token anywhere longer-lived than the session needs.
Your virtualId should be pseudonymous on the web for exactly the same reason it is in an app — it
travels to Cheggout, and on the web it also sits in the browser.