Offerwall for any website. Link, iframe, or button.
Put the Moonetix offerwall on any website, from WordPress to a custom app, with a signed link, an iframe, or a floating button. Your users earn your currency, and every reward reaches your server as a signed postback.
- 3Ways to show it
- 0SDKs to install
- HTTPSAny site, any stack
<iframe title="Offerwall"
src="https://wall.moonetix.com/APP_ID?user_id=USER_ID&hash=HASH"
style="border:0;width:100%;height:100vh"></iframe>Go live in three steps.
Copy the code, replace the placeholders with the values from your dashboard under Apps, your app, Integration, and test before you launch.
-
Build the signed link on your server
Every link carries the ID of your signed-in user and an HMAC-SHA256 hash made with your link hash salt. The hash stops anyone from changing the user ID to open the wall as someone else, so build it on your server and never put the salt in a page.
offerwall.php<?php // Build the link on your server, for the signed-in user $hash = hash_hmac('sha256', $userId, $linkHashSalt); $url = 'https://wall.moonetix.com/' . $appId . '?user_id=' . rawurlencode($userId) . '&hash=' . $hash;offerwall.js// Build the link on your server, for the signed-in user const crypto = require('crypto'); const hash = crypto.createHmac('sha256', linkHashSalt) .update(String(userId)) .digest('hex'); const url = `https://wall.moonetix.com/${appId}` + `?user_id=${encodeURIComponent(userId)}&hash=${hash}`;offerwall.py# Build the link on your server, for the signed-in user import hmac, hashlib from urllib.parse import quote uid = str(user_id) hash = hmac.new(link_hash_salt.encode(), uid.encode(), hashlib.sha256).hexdigest() url = f"https://wall.moonetix.com/{app_id}?user_id={quote(uid)}&hash={hash}" -
Show it the way that fits your site
Open the link from your menu, embed it on its own page, or add the floating button to every page. You can use more than one at once: all of them share the same rewards and postbacks.
earn.html<iframe title="Offerwall" src="https://wall.moonetix.com/{APP_ID}?user_id={USER_ID}&hash={HASH}" style="border:0;width:100%;height:100vh"></iframe>layout.html<script src="https://wall.moonetix.com/embed.js" async data-button-url="https://wall.moonetix.com/{APP_ID}?user_id={USER_ID}&hash={HASH}" data-button-text="Earn rewards" data-button-color="#004ABB" data-button-position="right"></script>menu.html<a href="https://wall.moonetix.com/{APP_ID}?user_id={USER_ID}&hash={HASH}" data-moonetix-open>Earn rewards</a> <script src="https://wall.moonetix.com/embed.js" async></script>Linkhttps://wall.moonetix.com/{APP_ID}?user_id={USER_ID}&hash={HASH}&sub1=homepage -
Credit rewards with the postback
Every reward reaches your server as a signed postback. Check the hash, add the reward once per transaction ID, and take it back if a later postback reverses it. Failed postbacks are retried up to 5 times.
Dashboard, Postback tabhttps://yoursite.com/postback?user={user_id}&tx={transaction_id}&status={status}&reward={reward}&hash={hash}postback.php<?php $tx = $_GET['tx'] ?? ''; $userId = $_GET['user'] ?? ''; $reward = $_GET['reward'] ?? ''; $status = $_GET['status'] ?? ''; $secret = getenv('MOONETIX_POSTBACK_SECRET'); $expected = hash_hmac('sha256', "$tx:$userId:$reward:$status", $secret); if (!hash_equals($expected, $_GET['hash'] ?? '')) { http_response_code(403); exit; } if ($status === '1') { credit_once($userId, $tx, $reward); // once per transaction ID } elseif ($status === '2') { reverse_if_credited($userId, $tx, $reward); } http_response_code(200);postback.jsconst crypto = require('crypto'); app.get('/postback', (req, res) => { const { tx, user, reward, status, hash } = req.query; const secret = process.env.MOONETIX_POSTBACK_SECRET; const expected = crypto.createHmac('sha256', secret) .update(`${tx}:${user}:${reward}:${status}`) .digest('hex'); const valid = typeof hash === 'string' && hash.length === expected.length && crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(expected)); if (!valid) return res.sendStatus(403); if (status === '1') creditOnce(user, tx, reward); // once per transaction ID if (status === '2') reverseIfCredited(user, tx, reward); res.sendStatus(200); });postback.pyimport hmac, hashlib, os from flask import request, abort @app.get("/postback") def postback(): a = request.args parts = [a.get(k, "") for k in ("tx", "user", "reward", "status")] msg = ":".join(parts) secret = os.environ["MOONETIX_POSTBACK_SECRET"].encode() expected = hmac.new(secret, msg.encode(), hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, a.get("hash", "")): abort(403) if a.get("status") == "1": credit_once(a["user"], a["tx"], a["reward"]) # once per transaction ID elif a.get("status") == "2": reverse_if_credited(a["user"], a["tx"], a["reward"]) return "", 200
- Castle MergeReach level 10+1,500
- FitTrackStart a free trial+2,000
- Word RushPlay 3 days in a row+450
- Budget PalSet up your first budget+800
Right on your page
The floating button opens the offerwall in a pop-up, so users never leave the page they are on.
Everything the wall does for you
- A full offerwall page
Earn and My offers tabs, search, categories, and sorting, with the offers that fit each user’s country and device.
- Your currency
Every reward is shown in your own currency name and icon, calculated with your conversion rate and user split.
- Your brand
Colors, corner radius, padding, font size, and the currency icon are set in your dashboard, with no code.
- Signed links
Link security is on by default, so nobody can open your wall as one of your users.
- Sub IDs
Add up to five of your own values, such as the page or campaign, and get them back in every postback and report.
- User support
Users follow their offers in My offers and can report a missing reward right from the offer.
Test it, then launch.
Everything you need to check before real users see your offerwall, with the tools built into your dashboard.
Open as a test user
In Integration status on the Integration tab, open your offerwall as the user owner-test. Test visits are not counted as users.
Check a link
Paste a link your site built, or type a user ID to see the exact link your server should build. The two must be identical.
Send a test postback
Choose the user, status, and payout, and see exactly what your server answered, with the response code and time. Test transaction IDs start with test_.
Test from a normal connection
VPNs, proxies, Tor, and cloud networks are blocked, so test on home Wi-Fi or mobile data, in a country where offers run.
Launch checklist
0 of 11 ready
Ready to launch. Your progress is saved in this browser.
Common errors, fixed fast.
What you might see while you integrate the Website, what causes it, and the fix.
Link not validThe hash does not match the user ID in the link.
FixSign the exact user ID with the link hash salt, not the postback secret key, as lowercase hex.
Missing user IDThe user ID is empty or has characters we do not accept.
FixUse 1 to 100 characters from A-Z a-z 0-9 . _ @ : + - and URL-encode it.
Blank iframe or pop-upThe page is not on the website you registered for the app, or it is not https.
FixEmbed it on an https page of that domain or a subdomain. For another site, add a new app.
No floating buttondata-button-url is missing or is not an offerwall link.
FixUse the full signed link that starts with https://wall.moonetix.com/.
VPN or Proxy detectedYou are testing through a VPN, a proxy, or a cloud network.
FixTest from a normal home or mobile connection.
Fewer offers than expectedYou hid some offers, or fewer offers run in that country or on that device.
FixOpen Offers in your dashboard, set Status to Hidden, and click Show to bring an offer back.
Postback log shows 403 or 404Your script rejected the postback, or the URL is wrong.
FixOpen the URL from the log in a browser and check your hash code.
Postback log shows a timeoutYour script takes longer than 6 seconds to answer.
FixAnswer with 200 first, and run slow work in the background.
Postback log shows 301 or 302Your URL redirects, for example from http to https.
FixUse the final URL. Postbacks do not follow redirects.
No match. See the full list in the docs or contact us.
At a glance
- Works on
- Any https website: WordPress, Next.js, Laravel, plain HTML, and more
- Ways to show it
- Link, iframe, floating button, or your own button
- Embed rules
- Frames and pop-ups load on the website you registered and its subdomains
- Script size
- One small script, only for the button and pop-up
- Rewards
- Signed server-to-server postback, retried up to 5 times
- Price
- Free for approved publishers
Other integrations
- Offers APIGet the offers as JSON and show them in your own design.
- Android SDKA native offerwall screen for Kotlin and Java apps.
- iOS SDKA native offerwall for Swift, SwiftUI, and Objective-C.
- Unity SDKRewarded offers for Android and iOS games, from C#.
- Flutter SDKOne Dart plugin for Android and iOS.
- React Native SDKFor React Native and Expo apps, with TypeScript types.
- All integrationsCompare them side by side.
Do I need to install anything to add an offerwall to my website?
No. The offerwall runs on Moonetix. You add a signed link to your site, embed it with an iframe, or load one small script for the floating button. Your server only builds the link and receives postbacks.
Does it work with WordPress?
Yes. Build the signed link in a small plugin or your theme with the PHP example, then embed it on an Earn page or add the floating button. The Academy has a step by step WordPress guide.
Why does the link need a hash?
The hash is an HMAC-SHA256 of the user ID, made with your link hash salt. It proves that your server created the link for that user, so nobody can change the user ID in the address bar and earn as someone else.
Why does the offerwall not load in my iframe?
For safety, frames and pop-ups only load on https pages of the website you registered for the app and its subdomains. Opening the link directly in a tab, a new window, or a mobile WebView works everywhere.
How do my users get their rewards?
Moonetix sends a signed postback to your server for every reward. Your server checks the hash and credits the user in your currency. A later reversal arrives with the same transaction ID, so you can take the reward back.
Can I choose which offers appear?
Yes. On the Offers page of your dashboard you can hide any offer, and it disappears from your offerwall, the embedded wall, the floating button, and the Offers API of that app.
Turn your traffic into earnings.
Create a free publisher account and earn from every offer your users complete on your website, app, game, or community.