Widget integration reference
The complete map of embeds, attributes, and API URLs: everything the ReTarget.gg widgets do, cross-linked.
One script per surface, two required attributes, one API. This page is the single source of truth for every attribute, URL, and behavior across the widget family.
Scripts at a glance
| Script | Doc | Use case |
|---|---|---|
widget.js | Geo-blocking widget | Full-page overlay when the visitor falls on the blocked side of your geo rule. |
widget-section.js | Section widget | Sponsored offers inside a container (mode=section on the decision API). |
widget-decline.js | Trigger Widget | Your server triggers the overlay after a decline path (KYC, deposit, etc.). |
iframe | Iframe fallback | Third-party popup/tag builders that only support iframes. |
All three scripts are served from https://cdn.retarget.gg/ (static CDN). The overlay modes mount into #retarget-root: the script creates it on first render.
Required attributes
Every script tag needs exactly these:
data-pub: the website's public key (pk_…).data-website: the website's website key (web_…).
Each website has its own pair. If you run multiple sites, each gets its own pk_ / web_ on its own dashboard page.
Optional attributes
| Attribute | Scope | Purpose |
|---|---|---|
data-api | all | Override the API base URL. Defaults to https://api.retarget.gg. Use for staging. |
data-comments="false" | all | Mute the script's console.log diagnostics. Purely a logging toggle: does not hide any visible label. |
data-debug | all | Force verbose debug logging (same effect as running on localhost). |
data-dev-country | all | Force a country (e.g. DE). Only honored on localhost or with data-allow-localhost. |
data-dev-region | all | Force a region (e.g. BY). Same localhost-only constraint. |
data-allow-localhost | all | Treat the current host as "localhost" for dev-override purposes (useful for tunnels). |
data-container | section | Default retarget-ads. Accepts a single id: not a list. |
data-max-ads | section | Cap the number of cards rendered. Default 6, hard cap 24. |
Section mode also needs a container on the page: <div id="retarget-ads"></div>.
Recommended install snippet
The "guarded loader" pattern below works everywhere: plain HTML, GTM, Cloudflare Zaraz, any tag manager. The querySelector guard prevents a double load when the tag fires twice on an SPA or GTM refire:
<script>
(function () {
if (document.querySelector('script[data-website="YOUR_WEBSITE_KEY"]')) return;
var s = document.createElement('script');
s.src = 'https://cdn.retarget.gg/widget.js';
s.async = true;
s.setAttribute('data-pub', 'YOUR_PUBLIC_KEY');
s.setAttribute('data-website', 'YOUR_WEBSITE_KEY');
s.setAttribute('data-api', 'https://api.retarget.gg');
(document.head || document.documentElement).appendChild(s);
})();
</script>Geo-blocking flow (widget.js)
Script loads
Reads its
data-*attributes and issuesGET /v1/decision?pub=…&website=….Decision returns
The API returns
{ allowed, requestId, country, region }.allowed=true→ the script emits aPOST /v1/events/snippet-pingand exits.allowed=false→ the widget fetches offers.Offers render
GET /v1/offers?website=…&requestId=…&country=…returns a ranked list. The widget creates#retarget-rootand renders the full-screen overlay.Impressions and clicks
The widget posts
POST /v1/events/impressionfor each rendered card andPOST /v1/events/clickbefore navigating throughGET /v1/r?t=…for attribution.
The page's Origin must match the domain registered on the website. Unknown origins get a 403 from /v1/decision with reason: "invalid_origin".
Section flow (widget-section.js)
Identical to geo-blocking with three differences:
GET /v1/decision?mode=sectionso analytics differentiate inline from overlay.allowed=falserenders cards into your container instead of creating an overlay.- Card density is tuned for inline layouts (up to
data-max-adscards, default 6).
Same keys, same origin rules, same events.
Trigger Widget flow (widget-decline.js)
For "we're not proceeding" flows where you still want alternative offers, with you deciding when the overlay opens.
One-time setup in the dashboard: Websites → [Your site] → toggle Trigger Widget to reveal the integration secret.
Browser: load widget-decline.js
POST /v1/widget-decline/session?pub=…&website=…returns asessionIdandexpiresAt(~15 min). The script setswindow.__RETARGET_DECLINE_SESSION_IDand dispatchesretarget:decline-sessionwithdetail: { sessionId }.Browser → your server
Send the
sessionIdto your backend via whatever transport fits your app (cookie-auth'd fetch, signed JWT, etc.).Your server → trigger
When ready,
POST /v1/widget-decline/triggerwithAuthorization: Bearer <integration_secret>and{ "sessionId": "..." }. Returns200with{ "ok": true }(or{ "ok": true, "alreadyTriggered": true }on a second call).Next poll sees status: ready → overlay renders
The embed is polling
GET /v1/widget-decline/session/{sessionId}every 2 seconds. Onreadyit fetches offers and renders.
Integration secret: server only
The integration secret is the only credential that can arm a Trigger Widget session. Keep it in server env vars or a secrets manager. Never in NEXT_PUBLIC_*, in git, or in client bundles.
API endpoints used by the widgets
The widgets call these on your behalf. You don't need to call them directly unless you're building custom integrations: but knowing what they do helps debug.
Full spec at /docs/api.
Browser events dispatched
Only the Trigger Widget currently dispatches a DOM event. The geo-blocking and section widgets do not emit custom events: if you want to forward widget activity to your own analytics stack, do it from your server via the events you receive in your dashboard, or subscribe to the API's webhook product (contact us).
| Event | Widget | detail |
|---|---|---|
retarget:decline-session | widget-decline.js | { sessionId: string } |
Example:
window.addEventListener("retarget:decline-session", (ev) => {
const { sessionId } = ev.detail;
console.log("ReTarget.gg decline session", sessionId);
});Origin and CORS
The widget's page Origin must match the domain registered on the website. The API enforces this on /v1/decision, /v1/offers, and /v1/widget-decline/*. Unknown origins get 403 Forbidden with reason: "invalid_origin".
Event endpoints (/v1/events/*) accept any origin: they're designed to be sendBeacon-friendly and CORS-safelisted (text/plain content type, no preflight).
Publisher app proxy (optional)
Instead of loading the script from https://retarget.gg/, you can proxy it through your own host (e.g. /widget.js mapped to https://cdn.retarget.gg/widget.js). When proxied, set the API base either via data-api on the script tag or by assigning window.RETARGET_API before the script loads (window.AFFILFINDER_API is still accepted as an alias).
Performance
- Single async script per surface.
- Allowed visitors: one
/v1/decisioncall, onesnippet-ping, nothing rendered. - Blocked visitors: decision + offers + events.
- API responses set
Cache-Control: no-store: decisions are per-request. Don't cache them in a CDN in front ofapi.retarget.gg. widget.jsrespects standard async loading: it never blocks first paint.
Related
Geo-blocking widget
Full-page overlay: attributes, iframe setups, verification.
Section widget
Inline placement with container options and layout tips.
Trigger Widget
Server-triggered overlay for post-KYC and other ineligible-user flows.
Iframe fallback
No-script path for popup builders.
API reference
/v1/* endpoints with request and response shapes.
Debugging
Troubleshoot installs, empty containers, missing events.
Publisher
Geo Popup & Decline Popup overview
The product framing for the install you just read.
Advertiser
CPC, CPA, eCPM in one auction
The demand side of the network — useful context even for publishers.
Essays
Long-form strategy
How others think about geo-blocking, KYC declines, and bid models.
Need help with setup?
Send us your website stack, target regions, and whether you are installing Geo Popup or Decline Popup.