How to Add an Offerwall to a Unity Game

Key takeaways

  • The game asks your backend for a signed link; the salt never ships inside the build.
  • Application.OpenURL is the simplest way to open it, and a WebView plugin keeps players inside the game at the cost of more testing.
  • Only your server credits currency, from verified postbacks, and the game reads the balance back when the player returns.

How do you add an offerwall to a Unity game?

To add an offerwall to a Unity game, have your game backend build a signed offerwall link for the logged-in player, open that link from the game with Application.OpenURL or a WebView plugin, and credit the player’s currency on your server when the offerwall sends a postback. The game never holds a secret and never decides that a reward was earned. When the player comes back, the game reloads the balance from your backend.

A web-based offerwall such as Sharklio’s needs no SDK, so nothing is added to your build except a button and a few lines of C#. The business side, such as where to place the wall and how to price your currency, is covered in Monetize a mobile game with an offerwall. This guide is the Unity implementation.

Who does what

PartDoesNever does
Unity clientAsks for the link, opens it, reloads the balanceHolds the salt or keys, adds currency by itself
Your backendSigns the link, receives postbacks, owns the walletTrusts the client about rewards
SharklioShows offers, tracks results, sends signed postbacksPays your players directly

For a mobile game, create a Sharklio app of the Direct link type. A direct link opens anywhere, with no website restriction. The iframe type is only for web pages, so it fits a WebGL build hosted on the website you registered for the app.

Step 1: an endpoint that returns the signed link

The offerwall link is https://wall.sharklio.com/{APP_ID}?user_id={USER_ID}&hash={HASH}. The hash is an HMAC-SHA256 of the user ID with your app’s link hash salt, in lowercase hex. Anything inside a game build can be extracted, so the salt lives on your backend only. A Node.js endpoint behind your normal player authentication:

const crypto = require('crypto');

app.get('/offerwall-link', requireAuth, (req, res) => {
  const userId = String(req.user.id);
  const hash = crypto.createHmac('sha256', process.env.SHARKLIO_LINK_SALT).update(userId).digest('hex');
  res.json({
    url: `https://wall.sharklio.com/${process.env.SHARKLIO_APP_ID}?user_id=${encodeURIComponent(userId)}&hash=${hash}`,
  });
});

Use your account ID, the one your wallet uses, as the user ID. Not a device ID, which changes on reinstall, and not an email address. If the same player also plays on your website, use the same ID there. PHP and Python versions are in the Offerwall link docs.

Step 2: open the link from Unity

The client calls your endpoint with the player’s session token, reads the URL, and opens it:

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class OfferwallButton : MonoBehaviour
{
    [Serializable]
    class LinkResponse { public string url; }

    public void OnEarnClicked()
    {
        StartCoroutine(OpenOfferwall());
    }

    IEnumerator OpenOfferwall()
    {
        using (UnityWebRequest req = UnityWebRequest.Get("https://api.yourgame.com/offerwall-link"))
        {
            req.SetRequestHeader("Authorization", "Bearer " + PlayerSession.Token);
            yield return req.SendWebRequest();
            if (req.result != UnityWebRequest.Result.Success)
            {
                ErrorToast.Show("Offers are not available right now.");
                yield break;
            }
            string url = JsonUtility.FromJson<LinkResponse>(req.downloadHandler.text).url;
            if (url != null && url.StartsWith("https://wall.sharklio.com/"))
            {
                Application.OpenURL(url);
            }
        }
    }
}

PlayerSession and ErrorToast stand for your own session and UI classes. Hook OnEarnClicked to a button in your shop or currency screen. Fetch a fresh link each time rather than storing one, so it always belongs to the player who is logged in now.

System browser or WebView plugin?

Application.OpenURL hands the link to the operating system, which opens it in the default browser. Unity’s engine API has no general-purpose in-game WebView for Android and iOS, so showing the offerwall inside the game means adding a WebView plugin, open-source or commercial. Both work with a Sharklio direct link:

Application.OpenURLWebView plugin
EffortOne lineA plugin, platform settings, and testing
Player stays in your UINo, the browser opensYes, with your own close button
App store links in offersHandled by the systemYou may need to pass them to the system
Screenshot upload for tasksWorks like any websiteThe plugin must support file inputs
Cookies and sign-insThe player’s own browserA separate web storage

Start with Application.OpenURL. Move to a WebView plugin only if leaving the game is a real problem for your players, and then test four things on real Android and iOS devices before release:

  • JavaScript is on. The offerwall needs it.
  • Store and app links leave the WebView. Many offers send players to an app store page. Most plugins let you intercept navigation; hand those links to Application.OpenURL.
  • File upload works. Task offers ask for a screenshot as proof, which uses a normal file input. Some WebView setups need extra configuration for it.
  • There is a way out. A visible close button, and a back button that goes back inside the offerwall before it closes the view.

If you weigh in-app browser tabs too, such as Custom Tabs on Android or SFSafariViewController on iOS, the trade-offs are in Offerwall integration: iframe, link or API?

Step 3: handle the return to the game

Rewards do not travel through the page back into Unity. They go from Sharklio to your server. So when the player comes back, ask your server:

void OnApplicationPause(bool paused)
{
    if (!paused)
    {
        StartCoroutine(Wallet.Refresh());
    }
}

Unity calls OnApplicationPause(false) when the app resumes, for example after the player switches back from the browser. With a WebView plugin, refresh when the view closes instead. Then set expectations in your UI:

  • Some offers credit within minutes, others after a review or a later step, so a reward is not always there on return.
  • If you turn on pending postbacks (status 3), you can show “on its way” items in your own UI.
  • A short notification such as “Your 450 gems have arrived” after a credit brings players back to spend them.

Step 4: credit through your backend, never the client

Anything the client says can be faked, so the client never reports a reward. Your backend credits the player only when a verified postback arrives:

StatusMeaningYour backend
1CreditedAdd the reward, once per transaction ID
2ReversedTake it back, only if you credited that transaction
3Pending (opt-in)Show it as on its way, do not credit
4RejectedNothing to credit

Verify the hash first: an HMAC-SHA256 of transaction ID, user ID, reward, and status joined with colons, signed with your postback secret key, which is a different value from the link salt. One transaction keeps the same ID for its whole life, so store the last status you handled and skip repeats after a retry. Answer with a 2xx status within 6 seconds, with no redirect. The full checklist is in Postback security: verify every reward call.

Decide early what happens when a player already spent currency that is later reversed, for example whether the balance can go below zero, and write it into your terms. For pricing the currency itself, see How to set your virtual currency exchange rate.

Store policies, in general terms

Apple and Google both have rules about incentives, and both update them, so read the current versions before you submit a build with an offerwall. The points that most often matter for games:

  • Never reward ratings or reviews, of your game or any other app.
  • Do not force players to install other apps to use your game. The offerwall should be an optional extra, not the core of the game.
  • Check the stricter rules for apps aimed at children. End users of a Sharklio offerwall must be at least 16 anyway.
  • Be careful with crypto rewards, which have their own rules on the App Store.

The section on store policies in Monetize a mobile game with an offerwall links to the relevant Apple and Google pages.

Step 5: test with a test player

  1. Create a test account in your game and note its user ID.
  2. In the Sharklio Integration tab, use Test a link with that ID and compare the result with what your endpoint returns. They must match exactly.
  3. Tap the button in a development build and check that the offerwall opens, not the Link not valid page.
  4. In the Postback tab, use Send a test postback for the test player’s ID with status 1. The balance in the game should go up once after a resume. Each test has its own new transaction ID starting with test_, so a status 2 test is for a transaction you never credited and must change nothing.
  5. With a WebView plugin, open a real offer that leads to a store page, and try a screenshot upload, on both Android and iOS.

Every postback attempt and your server’s answer is listed under Reports, Postbacks. The Testing and troubleshooting docs list the common errors and fixes.

A Sharklio offerwall for your Unity game, no SDK

A Sharklio app gives your game one signed direct link, your own currency name, icon, colors, and rate, and signed postbacks for every credit and reversal. Nothing ships inside your build, so you can add or move the entry point without updating a third-party SDK. Publisher applications open soon. Read how to get approved as a publisher and build your link endpoint and postback handler against the Quick start now.

Frequently asked questions

Do I need an SDK to add an offerwall to Unity?

Not for a web-based offerwall. Your backend signs a link, the game opens it, and your server credits players from postbacks.

Should I use Application.OpenURL or a WebView in Unity?

Start with Application.OpenURL, which opens the system browser and handles store links and uploads for you. Use a WebView plugin if keeping players inside the game matters enough to test store links, file uploads, and navigation on every platform.

Can the Unity client credit the reward when the player finishes an offer?

No. The client can be modified, so only your server credits currency, and only from verified postbacks.

Why is the reward not there when the player returns?

Many offers are credited after a review or a later step. Refresh the balance on every resume, and show pending items if you turned on pending postbacks.

Can I build the hash inside the game?

No. That would ship the salt in your build, and anyone who extracts it could open the offerwall as any player. Always sign the link on your backend.