Integration Docs
Everything you need to put Robins Ads on your website — normal display ads and full-screen interstitial ads, including the Reward API for games and apps. Setup takes about 2 minutes. You need a publisher account with an approved website (sign up free).
1. Normal display ads
Banners, skyscrapers, rectangles and native ads. Copy your personal snippet from Dashboard → Websites → your site → Ad Code — it already contains your Website ID.
Option A — automatic ads (easiest)
One script tag in your head. It finds the best ad positions on the page itself (in-article, sidebar, bottom):
<script src="https://robinsads.com/ads.js" data-website-id="YOUR_WEBSITE_ID" async></script>
Enable Automatic Ads in your website settings first.
Option B — fixed ad placements
Add the script once, then place an ad container wherever you want:
<!-- in <head> -->
<script src="https://robinsads.com/ads.js" data-website-id="YOUR_WEBSITE_ID" async></script>
<!-- anywhere in your <body> -->
<div class="adsense-ad"
data-website-id="YOUR_WEBSITE_ID"
data-ad-type="banner"></div>The data-ad-type attribute can be banner, skyscraper, rectangle, native, anchor, interstitial or popunder. Each placement requests only ads of that format that are allowed for your website (Website settings → Allowed Ad Types). The two overlay formats (interstitial, popunder) are not drawn inside the div — the div works as the trigger, so a click or tap on it opens the ad (see section 2).
| Attribute | On | Purpose |
|---|---|---|
| data-website-id | Script tag or ad div | Identifies your site — required everywhere |
| data-ad-type | Ad div | banner · skyscraper · rectangle · native · anchor · interstitial · popunder |
| data-interstitial | Script tag | Show a full-screen ad automatically (see section 2) |
| data-popunder | Script tag | Open the advertiser URL in a popunder window on click (see section 2c) |
2. Interstitial & popunder ads (overlay + new-window formats)
An interstitial covers the whole screen with a video or image. The user must watch it for its full duration (15–30 s) before it can be closed — our server verifies that watch time, so you can safely reward users who finish. When the video ends it fades into a Google-style end card showing the advertiser icon, name and a call-to-action button (Play Game, Download App, Visit Website), just like the interstitials in mobile games. One format, two ways to use it:
- Reward button — you put a "Watch ad, get 50 coins" button in your game/app and grant the reward after the verified watch.
- Automatic — the ad appears by itself once per visit between pages; no reward involved.
Step 1 — enable the format
In Dashboard → Websites → your site → Allowed Ad Types, tick interstitial and save. This makes the format eligible to serve on your site. Unlike popunder, an interstitial does not appear from the toggle alone — because it is a full-screen takeover it must be wired into the page with code (Step 2a or Step 2b). That way a page never suddenly covers the screen unless you asked for it.
Step 2a — reward button (callback)deprecated
Still works, but for rewards we now recommend the server-to-server Reward API (section 3) — it needs no browser callbacks and is impossible to fake. The base ads.js script from section 1 must be on the page. RobinAds.showInterstitial() shows the ad and resolves only after the watch is verified on our server:
<button id="watchAdBtn">▶ Watch ad · get 50 coins</button>
<script>
document.getElementById('watchAdBtn').addEventListener('click', function () {
RobinAds.showInterstitial().then(function (result) {
if (result.rewardGranted) {
// Full watch verified by our server - safe to reward:
giveRewardToMyUser(result.token); // coins, unlock, extra life...
} else {
console.log('No reward:', result.error || 'closed early');
}
}).catch(function (err) {
console.log(err.message); // e.g. "no ad available right now"
});
});
</script>The promise resolves with { rewardGranted, token, rewardId }. During the ad the user sees a countdown, then an end card with the advertiser icon, name and call-to-action button (e.g. "▶ Play Game" or "⬇ Download App") that they dismiss to close — that is the advertiser own reward path.
Step 2b — automatic interstitial
To have the interstitial show on its own (without a reward button), add data-interstitial="true" to the ads.js tag on the page where you want it. This is the only way an interstitial auto-appears — the Allowed Ad Types toggle by itself never triggers it.
<script src="https://robinsads.com/ads.js"
data-website-id="YOUR_WEBSITE_ID"
data-interstitial="true" async></script>
<!-- max 1 automatic ad per visit, 2-minute cooldown -->Step 2c — popunder ads (opens advertiser URL behind current tab)
A popunder ad opens the advertiser website in a new browser window behind the current tab using an anti-adblock form-submit technique. No creative image, no countdown, no overlay — just the URL. The advertiser only needs to provide a target URL and a title. Billed at $0.04 per 1,000 opens (publisher earns $0.02 per 1,000). The user does not notice the popunder until they close or navigate away from the current page, which makes this format highly effective and resilient against ad blockers.
Enable popunder in Allowed Ad Types to load popunder-eligible ads, then use a button or placement div to trigger the popunder:
<!-- 1) your own button (must be inside a click handler) -->
<button id="popunderBtn">Continue to site</button>
<script>
document.getElementById('popunderBtn').addEventListener('click', function () {
RobinAds.showPopunder().then(function (result) {
console.log('Popunder opened:', result.url);
}).catch(function (err) { console.log(err.message); });
});
</script>
<!-- 2) placement div used as a click trigger -->
<div data-website-id="YOUR_WEBSITE_ID" data-ad-type="popunder">Continue</div>Step 3 — valuable rewards? Verify server-sidedeprecated
Legacy flow only — the Reward API does this verification for you. If you still use the browser callback and coins can be traded for anything real, do not rely on it alone: send the token to your backend and check it against our API — this is impossible to fake, because the token is an HMAC signature over the server-stored impression:
// Your backend:
const res = await fetch('https://robinsads.com/api/ads/reward/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ impressionId: rewardId, token: tokenFromFrontend }),
});
const { verified } = await res.json();
// if (verified) → credit the user. Store rewardId so it is never granted twice.3. Reward API — server-verified rewards, the easy way
The recommended way to give your users rewards for watching ads — built like a payment gateway. Your backend creates a reward with one REST call, your visitor watches the ad in a popup we host (countdown, anti-fraud, billing — zero code on your side), and your backend polls the reward until it says "verified". There are no browser callbacks and nothing to fake: only our server can flip a reward to verified.
Getting started
- Create a free Robins Ads account and get your website approved.
- Open Dashboard → Settings → API Keys and create a key.
- Store the key on your server — it is shown only once. Never put it in front-end code.
- Send it as a Bearer token on every API call.
Base URL & authentication
https://robinsads.com/api/v1 Authorization: Bearer rbads_live_...
1 — Create a reward
POST /api/v1/rewards returns a popup_url — save the reward id in your database together with your user/order, then hand the URL to the visitor browser.
curl -X POST https://robinsads.com/api/v1/rewards \
-H "Authorization: Bearer rbads_live_..." \
-H "Content-Type: application/json" \
-d '{
"website_id": "YOUR_WEBSITE_ID",
"metadata": { "user_id": "user-42", "coins": 50 }
}'Response:
{
"id": "rbads_9f2k1a7c3e...",
"object": "reward",
"status": "pending",
"website_id": "69e6aa...",
"popup_url": "https://robinsads.com/reward/rbads_9f2k1a7c3e...?s=pub_51ab...",
"reward_id": null,
"verified_at": null,
"metadata": { "user_id": "user-42", "coins": 50 },
"created_at": "2026-09-30T12:00:00.000Z",
"expires_at": "2026-09-30T12:15:00.000Z"
}2 — Open the popup (visitor side)
That is the entire front-end integration — a button that opens the popup on a user gesture. The interstitial, countdown and verification all run on our page:
<button id="watchAdBtn">▶ Watch ad · get 50 coins</button>
<script>
document.getElementById('watchAdBtn').addEventListener('click', async function () {
// Ask YOUR backend (it calls POST /api/v1/rewards with the secret key)
const { popup_url } = await fetch('/my-backend/reward', { method: 'POST' }).then(function (r) { return r.json(); });
window.open(popup_url, 'robinads_reward', 'width=480,height=640');
// Then let your backend poll the reward id until it is "verified" - see step 3.
});
</script>3 — Read reward status
GET /api/v1/rewards/:id is the way to read a reward current status. There are no webhooks — check this endpoint whenever and however you like: on demand, on a timer, from a cron job or a background worker. When the status is verified, grant the reward — and store the id so it is never granted twice.
- pending — the visitor has not finished the ad yet (or has not opened the popup).
- verified — full watch confirmed by our server. Credit the user now.
- expired — the popup URL was not used within 15 minutes.
- rejected — a completion attempt failed verification (fraud attempt).
// Your backend - poll until a terminal state, then grant exactly once
const KEY = process.env.ROBINADS_API_KEY; // rbads_live_...
const BASE = 'https://robinsads.com/api/v1';
async function rewardStatus(id) {
const res = await fetch(BASE + '/rewards/' + id, {
headers: { Authorization: 'Bearer ' + KEY },
});
return res.json(); // { id, status, reward_id, verified_at, metadata, ... }
}
const timer = setInterval(async () => {
const reward = await rewardStatus(savedRewardId);
if (['verified', 'expired', 'rejected'].includes(reward.status)) {
clearInterval(timer); // terminal - stop polling
if (reward.status === 'verified' && !(await alreadyGranted(reward.id))) {
await giveCoins(reward.metadata.user_id, reward.metadata.coins);
await markGranted(reward.id); // dedupe by reward id, forever
}
}
}, 5000);Errors & rate limits
Errors are returned as JSON {"error": "message"} with the appropriate HTTP status code. Requests are rate-limited per IP (120 per minute). On 429, back off and retry.
- 401 — missing or invalid API key
- 403 — website not verified or approved
- 404 — reward not found (wrong id or not yours)
- 429 — rate limit exceeded
4. Telegram Mini Apps, bots & mini games
Run the same display ads and the full-screen rewarded view inside a Telegram bot, Mini App or mini game — no extra code, no SDK to wire up. A Telegram Mini App is just a web page, so you use the exact ads.js snippet from section 1. When it detects it is running inside Telegram it automatically adapts: ad clicks open through Telegram bridge (so they never get swallowed by the in-app browser), the full-screen ad expands to fill the mini-app viewport, and the native Back button closes an ad once the required watch is done.
Easy install for owners — 4 steps
- Add your Mini App as a website. In Dashboard → Websites → Add website, enter the HTTPS domain that hosts your Mini App (the same URL you give BotFather). Verify and wait for approval — your ads only serve once the site is approved.
- Turn on the formats. Open your site → Allowed Ad Types, tick banner, rectangle, native and interstitial, then copy your Website ID from Ad Code.
- Point BotFather at your page. In @BotFather → your bot → Bot Settings → Menu Button / Mini App, set the Web App URL to that HTTPS domain.
- Paste one script tag. Drop the snippet below into your Mini App head — the script handles Telegram detection for you, so you never include or initialise the Telegram SDK yourself.
<!-- 1) once in <head> — works on normal sites AND inside Telegram -->
<script src="https://robinsads.com/ads.js" data-website-id="YOUR_WEBSITE_ID" async></script>
<!-- 2) a banner anywhere in your Mini App -->
<div data-website-id="YOUR_WEBSITE_ID" data-ad-type="banner"></div>
<!-- 3) rewarded full-screen ad: "watch an ad, get a reward" button -->
<button id="watchAdBtn">▶ Watch ad · get coins</button>
<script>
document.getElementById('watchAdBtn').addEventListener('click', function () {
RobinAds.showInterstitial().then(function (result) {
if (result.rewardGranted) {
giveRewardToMyUser(result.token); // coins, extra life, unlock… (server-verified)
}
}).catch(function (err) {
console.log(err.message); // e.g. "no ad available right now"
});
});
</script>That is the whole integration. It is identical on a normal website and inside a Telegram Mini App — the same snippet, the same data-ad-type containers and the same RobinAds.showInterstitial() call. The only difference is that inside Telegram the clicks, fullscreen and Back button are handled automatically.
5. Live demo — try it right here 🎮
real ads from the live networkThese buttons run the exact code from the docs above, using a demo website ID. Display formats load an ad into the box below; the interstitial plays full-screen with its countdown and — after our server verifies the watch — credits this demo with 50 coins, the same way a publisher game would reward a player.
Pick a format above to fetch a real ad.
Demo only: impressions here count against real advertiser campaigns just like any placement. No reward is actually paid out — the coin counter just shows where your own reward logic goes.
6. Rates — what advertisers pay, what you earn
| Format | Advertiser pays | Publisher earns (50%) |
|---|---|---|
| Banner / skyscraper / rectangle / native | $0.40 per 1000 views (CPM) | $0.20 per 1000 views |
| Interstitial / popup — complete view | $0.60 per 1000 fully-watched views | $0.30 per 1000 complete views |
| Click (any format) | $0.08 per click (CPC) | $0.04 per click |
Interstitials are a premium format: the advertiser is charged only when the watch time is fully completed and verified — skipped ads cost nothing. That is why they pay slightly more per view than standard display ads. Earnings are credited to your balance automatically.
7. Fraud protection — built in
- Watch time is measured on the server — from the moment the impression was created, never from the player clock. A claim before the countdown really elapsed is rejected.
- Tab-hidden / paused detection — the countdown in the ad player freezes when the tab is hidden or the video pauses.
- Daily per-user caps — one visitor can complete the same interstitial a limited number of times per day (default 10).
- IP abuse blocking — bots and rapid-fire IPs are blocked automatically for view and click events.
- Signed reward tokens — HMAC-signed, verified with constant-time comparison; replaying a claim returns the original token without double-billing.
- Origin check — completion claims are only accepted from the domain the ad was served on.
8. Creating an interstitial ad (advertiser side)
- Dashboard → Ads → Create Ad, choose type Interstitial — or hit the play button in the live demo above to see how it looks.
- Upload your creative — either an image or a video (MP4 / WebM, max 50 MB) in the same uploader. Videos play full-screen; images are shown full-screen for the countdown.
- Set the required watch time (15–30 seconds) and your CTA link — e.g. an app store page ("Download this app") or your website.
- Submit. Approved ads are served to every publisher who enabled the interstitial format.
You are only charged $0.60 per 1000 fully watched views — plus $0.08 CPC if a user clicks your CTA after the ad.
Ready to earn?
Sign up, add your website and paste the snippet — your first ads run within minutes.
Questions? Email info@robinswebdesign.com — Technical documentation for the Robins Ads ad network. Last updated 2026.