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>data-ad-type can be banner, skyscraper, rectangle or native. Each placement requests only ads of that format that are allowed for your website (Website settings → Allowed Ad Types).
| 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 |
| data-interstitial | script tag | Show a full-screen ad automatically (see section 2) |
2. Interstitial ads (full-screen, with reward option)
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 cardshowing the advertiser's 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.
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 baseads.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's icon, name and call-to-action button (e.g. "▶ Play Game" or "⬇ Download App") that they dismiss to close — that is the advertiser's own reward path.
Step 2b — automatic interstitial
<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 3 — valuable rewards? Verify server-sidedeprecated
Legacy flow only — the Reward APIdoes this verification for you. If you still use the browser callback and coins can be traded for anything real, don't 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 apopup_url — save the reward idin your database together with your user/order, then hand the URL to the visitor's 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's 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's 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 hasn't finished the ad yet (or hasn't opened the popup).
- verified — full watch confirmed by our server. Credit the user now.
- expired — the popup URL wasn't 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/invalid API key
- 403 — website not verified/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's 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.
RobinAds.showInterstitial() (section 2). The hosted-popup flow of the Reward API uses window.open(), which Telegram blocks inside a Mini App.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's
<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's 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.50 per 1000 views (CPM) | $0.25 per 1000 views |
| Interstitial — complete view | $0.80 per 1000 fully-watched views | $0.40 per 1000 complete views |
| Click (any format) | $0.10 per click (CPC) | $0.05 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's 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 ▶ 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.80 per 1000 fully watched views — plus $0.10 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 [email protected] — Technical documentation for the Robins Ads ad network. Last updated 2026.