# WebView & Direct Link

Although we provide support for WebView or direct-link integration, **this is not the recommended approach**. Whenever possible, you should integrate our **official SDK** instead.

#### Using the SDK ensures:

* **Better tracking accuracy** — SDK handles device signals and user sessions more reliably
* **Stronger fraud protection** — Anti-fraud checks and security layers are baked into SDK flows
* **Automatic updates** — You benefit from improvements and bug fixes without touching your integration
* **Faster integration** — No need to manually handle WebView setup, edge cases, or command bridges

> WebView or direct links should only be used in special cases where SDK usage is not possible (e.g., HTML-based apps, low-code platforms). Even then, you must strictly follow the rules in this guide to ensure reliability.

Your offerwall can be integrated either with our SDK or by embedding the URL directly via WebView. If you’re using **WebView or direct links**, please follow the instructions below to avoid common issues.

## 1. Building the Offerwall URL

You **must** append correct parameters to ensure tracking and reward delivery.

**Base URL:**

```
https://sdk.mychips.io/content
```

**Required Parameters:**

* `content_id` – your assigned adunit ID
* `user_id` – a unique user ID on your side (can be a hash or UUID or numeric)
* `webview` – bool

**Optional But Highly Recommended**

* `gaid`– Google Advertising ID is a unique, randomly generated identifier assigned by Google to Android devices, which enables advertisers to track and measure users’ advertising interactions across apps and services.&#x20;
* `idfa`– Identifier for Advertisers is a unique, randomly generated code that Apple assigns to each user’s device, allowing advertisers to monitor and analyze advertising-related activity.
* `gender` – `m`, `f`, or `o`
* `age` – user age (numeric 0-100)
* `os_version` – version of the os

#### **Final URL Example for iOS users:**

```
https://sdk.mychips.io/content?content_id={your_adunit_id]&user_id={your_user_id}&idfa={your_user_idfa}&age={your_user_age}&gender={your_user_gender}&webview=1
```

**Example final URL with values replaced for iOS users:**

```
https://sdk.mychips.io/content?content_id=28617c7e-0178-4b89-b258-74bcf171e&user_id=5d41402abc4b2a76b9719d911017c592&idfa=AEBE52E7-03EE-455A-B3C4-E57283966239&age=27&gender=f&webview=1
```

#### **Final URL Example for** ANDROID **users:**

```
https://sdk.mychips.io/content?content_id={your_adunit_id]&user_id={your_user_id}&gaid={your_user_gaid}&age={your_user_age}&gender={your_user_gender}&webview=1
```

**Example final URL with values replaced for ANDROID users:**

```
https://sdk.mychips.io/content?content_id=28617c7e-0178-4b89-b258-74bcf171e&user_id=5d41402abc4b2a76b9719d911017c592&gaid=9b2f0c84-17a3-4f19-9c51-3e8b0a7c3c91&age=27&gender=f&webview=1
```

## Best Practice WebView

These **must** be followed when integrating the offerwall via WebView or a direct link. Failure to implement them may result in **broken reward flows**, **missing tracking**, or **bad UX**.

| ✅ Rule                                                                                                            | ❓ Why It Matters                                                                                                                     | 🛠 What to Do                                                                                                                                                                                   |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content_id` & `user_id` &`webview=1` are **mandatory**                                                           | Without them, users can't be identified and rewards can't be tracked                                                                 | Append both in the URL: `?content_id=...&user_id=...`                                                                                                                                           |
| `gaid` &`idfa` are **highly recommended**.                                                                        | We highly recommend including the **GAID** or **IDFA** parameter, depending on the platform, as this helps improve eCPM performance. | <p></p><p>Append the parameter to the URL depending on the platform:</p><ul><li><strong>iOS:</strong> <code>?idfa=...</code></li><li><strong>Android:</strong> <code>?gaid=...</code></li></ul> |
| Enable **JavaScript** in WebView                                                                                  | Required for rendering and logic of the offerwall                                                                                    | `webView.getSettings().setJavaScriptEnabled(true);`                                                                                                                                             |
| Enable **DOM Storage**                                                                                            | Enables session/localStorage — often used by the offerwall                                                                           | `webView.getSettings().setDomStorageEnabled(true);`                                                                                                                                             |
| Disable **WebView cache**                                                                                         | Prevents bugs from loading outdated or broken content                                                                                | `webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);`                                                                                                                                |
| Open URLs that start with `https://api.mychips.io` **and whose path contains `redirect`** in an external browser. | These are used for conversion tracking and if not well implemented could affect trackability                                         | Open External Browser                                                                                                                                                                           |
| Handle `mychips://` URL scheme                                                                                    | Bridge used by offerwall to trigger native logic (e.g. reward sync)                                                                  | override and ignore this schema                                                                                                                                                                 |
| Add a **custom error page** on failure                                                                            | Prevents user from seeing a blank screen when offline or error occurs                                                                | Override `onReceivedError()` and show fallback HTML content                                                                                                                                     |
| Implement proper **back navigation logic**                                                                        | Prevents broken UX and enables going back within the WebView                                                                         | close activity on back press when url contains "**home"**                                                                                                                                       |
| **Support file uploads in WebView**                                                                               | support require file/image upload/                                                                                                   | Use `WebChromeClient.onShowFileChooser()` and route result back via `onActivityResult()`                                                                                                        |
| **Do not preload**                                                                                                | preloading will affect impression tracking and impact eCPM negatively                                                                | <p><br></p>                                                                                                                                                                                     |

## Code Example

Below are sample codes for different languages.&#x20;

**Note:** Replace the values of the Offerwall URL parameters with your actual data. The values used in the code example are for demonstration purposes only.

{% tabs %}
{% tab title="Android (Java)" %}

```java
// Initialize the WebView and configure it
WebView webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // External link handling
        if (url.startsWith("https://api.mychips.io") && url.contains("redirect")) {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(intent);
            return true;
        }
        // Custom scheme handling
        if(url.startsWith("mychips://")) {
            // Trigger native logic here (e.g., reward synchronization)
            return true;
        }
        return false;
    }
    
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        // Load error page
        view.loadData("<html><body><h3>Failed to load. Please try again later.</h3></body></html>", "text/html", "UTF-8");
    }
});

String url = "https://sdk.mychips.io/content?content_id=28617c7e-0178-4b89-b258-74bcf171e&user_id=5d41402abc4b2a76b9719d911017c592&gaid=9b2f0c84-17a3-4f19-9c51-3e8b0a7c3c91&age=27&gender=f&webview=1";
webView.loadUrl(url);

```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
// Initialize the WebView and configure it
val webView = findViewById<WebView>(R.id.webview)
webView.settings.apply {
    javaScriptEnabled = true
    domStorageEnabled = true
    cacheMode = WebSettings.LOAD_NO_CACHE
}

webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        url?.let {
          if (it.startsWith("https://api.mychips.io") && it.contains("redirect")) {
                startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it)))
                return true
            }
          if(it.startsWith("mychips://")){
                // Handle native logic here, e.g., reward synchronization
                return true
            }
        }
        return false
    }
    
    override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
        view?.loadData("<html><body><h3>Failed to load. Please try again later.</h3></body></html>", "text/html", "UTF-8")
    }
}

val url = "https://sdk.mychips.io/content?content_id=28617c7e-0178-4b89-b258-74bcf171e&user_id=5d41402abc4b2a76b9719d911017c592&gaid=9b2f0c84-17a3-4f19-9c51-3e8b0a7c3c91&age=27&gender=f&webview=1"
webView.loadUrl(url)

```

{% endtab %}

{% tab title="Android(Dart)" %}

<pre class="language-dart"><code class="lang-dart">import 'dart:io';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Offerwall Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const OfferwallPage(),
    );
  }
}

class OfferwallPage extends StatefulWidget {
  const OfferwallPage({super.key});
  @override
  State&#x3C;OfferwallPage> createState() => _OfferwallPageState();
}

class _OfferwallPageState extends State&#x3C;OfferwallPage> {
  late final WebViewController _controller;

  final String offerwallUrl = Uri.https(
    'sdk.mychips.io',
    '/content',
    {
      'content_id': '28617c7e-0178-4b89-b258-74bcf171e',
      'user_id': '5d41402abc4b2a76b9719d911017c592',
      'gaid': '9b2f0c84-17a3-4f19-9c51-3e8b0a7c3c91',
      'age': '27',
      'gender': 'f',
      'webview': '1',
    },
  ).toString();

  bool _isLoading = true;

  @override
  void initState() {
    super.initState();

    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..clearCache()
      ..clearLocalStorage()
      ..setBackgroundColor(const Color(0x00000000))
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageStarted: (String url) {
            setState(() => _isLoading = true);
          },
          onPageFinished: (String url) {
            setState(() => _isLoading = false);
          },
          onNavigationRequest: (NavigationRequest request) async {
            final url = request.url;

            
            if (url.startsWith('mychips://')) {
              _syncRewardFromUri(url);
              return NavigationDecision.prevent;
            }

            
           if ((url.startsWith('https://api.mychips.io') &#x26;&#x26; url.contains('redirect'))) {
              final uri = Uri.parse(url);
              if (await canLaunchUrl(uri)) {
                  await launchUrl(uri, mode: LaunchMode.externalApplication);
              }
              return NavigationDecision.prevent;
<strong>            }
</strong>
            return NavigationDecision.navigate;
          },
          onWebResourceError: (WebResourceError error) {
            _controller.loadHtmlString(
              '&#x3C;html>&#x3C;body>&#x3C;h3>Failed to load. Please try again later.&#x3C;/h3>&#x3C;/body>&#x3C;/html>',
            );
          },
        ),
      )
      ..loadRequest(Uri.parse(offerwallUrl));
  }

  void _syncRewardFromUri(String uriString) {
    final uri = Uri.parse(uriString);
    final amount = uri.queryParameters['amount'];
    final currency = uri.queryParameters['currency'];

    if (amount != null &#x26;&#x26; currency != null) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('You received $amount $currency')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final currentUrl = await _controller.currentUrl() ?? '';
        if (currentUrl.contains('/home')) {
          return true;
        }
        if (await _controller.canGoBack()) {
          _controller.goBack();
          return false;
        }
        return true;
      },
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Offerwall'),
          leading: IconButton(
            icon: const Icon(Icons.arrow_back),
            onPressed: () async {
              if (await _controller.canGoBack()) {
                _controller.goBack();
              } else {
                Navigator.of(context).pop();
              }
            },
          ),
        ),
        body: Stack(
          children: [
            WebViewWidget(controller: _controller),
            if (_isLoading)
              const Center(child: CircularProgressIndicator()),
          ],
        ),
      ),
    );
  }
}


</code></pre>

{% endtab %}

{% tab title="IOS(Swift)" %}

```swift
import UIKit
import WebKit

class OfferwallViewController: UIViewController, WKNavigationDelegate {
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.preferences.javaScriptEnabled = true
        // Use non-persistent data storage to disable caching
        webConfiguration.websiteDataStore = .nonPersistent()
        
        webView = WKWebView(frame: self.view.frame, configuration: webConfiguration)
        webView.navigationDelegate = self
        self.view.addSubview(webView)
        
        if let url = URL(string: "https://sdk.mychips.io/content?content_id=28617c7e-0178-4b89-b258-74bcf171e&user_id=5d41402abc4b2a76b9719d911017c592&idfa=AEBE52E7-03EE-455A-B3C4-E57283966239&age=27&gender=f&webview=1") {
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }
    
    // Display an error page if loading fails
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        let errorHTML = "<html><body><h3>Failed to load. Please try again later.</h3></body></html>"
        webView.loadHTMLString(errorHTML, baseURL: nil)
    }
    
    // Handle external links and custom URL schemes
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
                 decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let urlString = navigationAction.request.url?.absoluteString {
            if urlString.hasPrefix("https://api.mychips.io") && urlString.contains("redirect") {

                if let redirectUrl = URL(string: urlString) {
                    UIApplication.shared.open(redirectUrl)
                    decisionHandler(.cancel)
                    return
                }
            }

            if urlString.hasPrefix("mychips://") {
                // Handle native logic here, e.g., reward synchronization
                decisionHandler(.cancel)
                return
            }
        }
        decisionHandler(.allow)
    }
}

```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mychips.io/webview-and-direct-link.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
