# Welcome

Welcome to TyrAds SDK Documentation.

This documentation provides all the information needed to start using the TyrAds SDK libraries.


# Start Here

The Tyr SDK empowers you to seamlessly integrate our campaigns into your application, enabling you to efficiently monetize your audience with ease and effectiveness.

## Integration Requirement

### Provide Currency Icon And Currency Conversion

For you to integrate the Tyr SDK and to show the user the currency in your own native environment please provide the following details to us.&#x20;

1. Currency Icon
   1. A 50x50 icon of your own native currency
2. Currency Conversion from $1&#x20;
   1. The value of $1 in your native app currency

{% hint style="info" %}
If you use Dollars or local currency as your currency Icon and Currency conversion please notify your Tyrads Representative.&#x20;
{% endhint %}

### Request API key and secret

Before you can integrate and test the SDK with your application, you must obtain an API key and API secret for your app within our Solutions dashboard. Please refer to the documentation (section 1.1) below for more information on integration setup in Solutions dashboard.&#x20;

{% content-ref url="/pages/wA6KNwNFL96U0Tpn5ZNv" %}
[Postback Payout (S2S) and Setup](/getting-started/postback-payout-s2s-and-setup)
{% endcontent-ref %}

* API key is a 32 hexadecimal string
* API secret is a 92 hexadecimal string

Example of API key and API secret:

```
API_KEY=4f0abc99e38e49b8b52804116e698a45
API_SECRET=cd3c34a55a3b75a3fdd928774615d4e142dd2e6a8ce9da14df4205c7cc812ce81d3656e3dc2c0c58ed05c75c57f87a3431fed62725bb0286f9461521b6c9998b
```

{% hint style="warning" %}
Please be sure to keep your API key and secret secure! Do not share them in emails, chat messages, client-side code, or publicly accessible sites.

If you have accidentally shared an API key and secret publicly, please contact the TyrAds team to revoke it
{% endhint %}

{% hint style="info" %}
API key and API secret for integrating SDK are different from the API key and secret for Advertiser API or Publisher API
{% endhint %}

## Receiving Payouts

To be able to receive payouts for the earnings your user generates, please go to the following page for more information:

{% content-ref url="/pages/wA6KNwNFL96U0Tpn5ZNv" %}
[Postback Payout (S2S) and Setup](/getting-started/postback-payout-s2s-and-setup)
{% endcontent-ref %}

## SDK Platforms

The platforms supported by the Tyr SDK are as follows:

#### Flutter

{% content-ref url="/pages/ErwohQap4AotmCU6aZrG" %}
[Flutter](/flutter/prerequisite)
{% endcontent-ref %}

#### Unity

{% content-ref url="/pages/9L33BUigsDiT9FYPw9sQ" %}
[Unity](/unity/prerequisite)
{% endcontent-ref %}

#### Web / Iframe

{% content-ref url="/pages/EakABNoxl8eC1Me5vc1j" %}
[IFRAME](/iframe/installation)
{% endcontent-ref %}


# Postback Payout (S2S) and Setup

In order for users to redeem their accumulated rewarded plays, they must be disbursed. Each reward can only be claimed once.

## 1.  Server to Server (S2S) Payout

To utilize server-to-server payout, you must establish an endpoint on your server. This endpoint will be requested by us to notify you of the user's rewards. Upon receiving the notification, it will be your responsibility to deliver it to the user.

We strongly advise implementing server-to-server payout for rewards, as it offers increased security and enhanced transparency on your part.

{% hint style="info" %}
Please contact TyrAds team for dashboard access and setup your endpoint URL within our Solutions dashboard.
{% endhint %}

## 1.1 Postback Setup in Solutions Dashboard

{% stepper %}
{% step %}

### Login

Log in to the Solutions Dashboard and navigate to Monetization > SDK Integration.
{% endstep %}

{% step %}

### Adding Media Asset

Click Add App or select Edit on an existing Media Asset.
{% endstep %}

{% step %}

### Postback URL&#x20;

Under Step 2: Adding Ad Unit, locate the Postback URL field.
{% endstep %}

{% step %}

### Setup

Enter your endpoint URL. This is the most critical part of the setup required to track user activity and reward users.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
Please refer to the guide below for more information and details on integration setup within Solutions dashboard. Please also note that API credentials can be found within the Media Asset/App after the integration setup in dashboard is done.
{% endhint %}

{% file src="/files/Jh2j2ZLdsOxN1Dq0N8J3" %}

## 1.2 HTTP Request Structure

Your endpoint will be invoked via `HTTP` request with `GET` method.  The parameters of the request are as follows:

<table><thead><tr><th width="257.0078125">Paramater</th><th width="120">Data Type</th><th>Description</th></tr></thead><tbody><tr><td><code>conversion_status</code></td><td>enum</td><td>The status of conversion. Enum: <code>approved</code>, <code>rejected</code></td></tr><tr><td><code>conversion_type</code></td><td>enum</td><td>The type of conversion: Enum: <code>install</code>, <code>event</code></td></tr><tr><td><code>cost</code></td><td>decimal</td><td>The payout amount you earn from Tyrads in U.S. Dollars. </td></tr><tr><td><code>user_payout_converted</code></td><td>decimal</td><td>The payout amount the user earns based on the currency conversion set.</td></tr><tr><td><code>timestamp</code></td><td>integer</td><td>The UNIX timestamp of the conversion </td></tr><tr><td><code>publisher_user_id</code><sup><strong>*Mandatory</strong></sup></td><td>string</td><td>The unique user id of the publisher used to identify the user</td></tr><tr><td><code>conversion_id</code></td><td>integer (format: <code>int64</code>)</td><td>The unique conversion ID can be used for deduplication if the <code>conversion_type</code> is <code>install</code> or <code>event</code>. </td></tr><tr><td><code>postback_id</code></td><td>integer (format: <code>int64</code>)</td><td>The unique postback ID can be used for deduplication.</td></tr><tr><td><code>app_name</code></td><td>string</td><td>The name of the app</td></tr><tr><td><code>event_name</code></td><td>string</td><td>The name of the event</td></tr><tr><td><code>sub3</code></td><td>string</td><td>The sub3 value, this can be any value you want and can be used to send to us on the click.</td></tr><tr><td><code>sub4</code></td><td>string</td><td>The sub4 value, this can be any value you want and can be used to send to us on the click.</td></tr><tr><td><code>ad_unit_id</code></td><td>string</td><td>The unique ad unit identifier </td></tr><tr><td><code>currency_name</code></td><td>string</td><td>The name of the currency </td></tr></tbody></table>

Example of Postback URL Setup:

{% tabs %}
{% tab title="Example Postback URL Setup" %}
[https://examplepostbackurl.com?conversion\_id={conversion\_id}\&conversion\_status={conversion\_status}\&conversion\_type={conversion\_type}\&event\_name={event\_name}\&app\_name={app\_name}\&app\_event\_id={app\_event\_id}\&payout={cost}\&timestamp={timestamp}\&publisher\_user\_id={publisher\_user\_id}\&user\_payout={user\_payout\_converted}\&postback\_id={postback\_id}\&sub3={sub3}\&sub4={sub4}\&ad\_unit\_id={ad\_unit\_id}](https://examplepostbackurl.com?conversion_id={conversion_id}\&conversion_status={conversion_status}\&conversion_type={conversion_type}\&event_name={event_name}\&app_name={app_name}}\&app_event_id={app_event_id}\&payout={cost}\&timestamp={timestamp}\&publisher_user_id={publisher_user_id}\&user_payout={user_payout_converted}\&rewarded_play_id={rewarded_play_id}\&postback_id={postback_id}\&sub3={sub3}\&sub4={sub4}\&ad_unit_id={ad_unit_id})
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Please note that variables like \&payout on the left can be adjusted to match your parameters. Meanwhile, the macros on the right, such as {cost}, need to adhere to the macro names listed in the table above.

Unused macros such as sub2, sub3, or sub4 can be omitted if no values are being passed through them during initialization of SDK.
{% endhint %}

## 2. Security \[Optional]

Verification Token

To verify the authenticity of incoming requests, kindly reach out to the TyrAds team. Upon request, we will provide you with a verification token that you can add in your postback, enabling you to confidently authenticate requests coming from our platform.

To verify the authenticity of incoming requests, kindly reach out to the TyrAds team. Upon request, we will provide you with the verification token to be added into the Postback, enabling you to authenticate data originating from our platform.

## 3. Enhanced Security with X-Tyrads-Token \[Optional]

### Overview

The `X-Tyrads-Token` header provides cryptographic verification for postback requests, ensuring that data has not been tampered with and originates from TyrAds. This enhancement adds an extra layer of security beyond the basic verification token.

### How It Works

When TyrAds sends a postback to your endpoint, we include an `X-Tyrads-Token` header containing a digitally signed token. This token is generated using HMAC-SHA256 and is unique to each request.

#### Key Security Features

* **Data Integrity**: Detects any modification to URL parameters
* **Authenticity**: Verifies requests originate from TyrAds
* **Replay Protection**: Timestamp prevents reusing old tokens
* **Uniqueness**: Each token contains a unique nonce

### Token Structure

```
{version}.kid={keyId}.ts={timestamp}.nonce={nonce}.sig={signature}
```

| Component | Description                               |
| --------- | ----------------------------------------- |
| `version` | Token version (v1, v2, v3, etc.)          |
| `kid`     | Key identifier for your publisher account |
| `ts`      | Unix timestamp (seconds)                  |
| `nonce`   | 32-character hex string for uniqueness    |
| `sig`     | 64-character HMAC-SHA256 signature        |

### Setup

#### 1. Enable X-Tyrads-Token

Contact the TyrAds team to:

* Enable X-Tyrads-Token for your publisher account
* Receive your encrypted security key
* Get your key ID & Version

#### 2. Request Structure

```http
GET https://your-server.com/postback?user_id=12345&event=purchase&amount=99.99&type=event
Headers:
  X-Tyrads-Token: v1.kid=1.ts=1700000000.nonce=a1b2...sig=d4e5...
```

{% hint style="info" %}
The version prefix (v1, v2, v3, etc.) may vary. Your verification logic should handle different token versions.
{% endhint %}

### Implementation

#### Basic Verification Flow

```javascript
async function handlePostback(req, res) {
  // 1. Extract token from header
  const token = req.headers['X-Tyrads-Token'];
  
  if (!token) {
    return res.status(401).json({ error: 'Missing X-Tyrads-Token' });
  }
  
  // 2. Get full URL
  const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
  
  // 3. Verify token
  const isValid = await verifyToken(token, fullUrl);
  
  if (!isValid) {
    return res.status(403).json({ error: 'Invalid token' });
  }
  
  // 4. Process postback
  await processPostback(req.query);
  return res.status(200).json({ success: true });
}
```

#### Token Verification

The verification algorithm:

1. Parse token components (version, keyId, timestamp, nonce, signature)
2. Fetch your security key using the keyId
3. Validate timestamp (tokens older than 5 minutes are rejected) (It depends upon your needs as well,&#x20;
4. Validate nonce (ensure it hasn't been used before to prevent replay attacks)
5. Reconstruct the signing payload:
   * Extract all URL query parameters
   * Sort parameters alphabetically by key
   * Format: `param1=value1&param2=value2&ts={timestamp}&nonce={nonce}`
6. Calculate HMAC-SHA256 signature with your secret key
7. Compare signatures using timing-safe comparison

#### Node.js Verification Example

```javascript
const crypto = require('crypto');

// In-memory nonce store (use Redis or database in production)
const usedNonces = new Set();

async function verifySignedToken(token, url) {
  try {
    // Parse token
    const parts = token.split('.');
    if (parts.length !== 5 || !parts[0].startsWith('v')) {
      return false;
    }
    
    const version = parts[0];
    
    const keyId = parts[1].replace('kid=', '');
    const timestamp = parts[2].replace('ts=', '');
    const nonce = parts[3].replace('nonce=', '');
    const providedSignature = parts[4].replace('sig=', '');
    
    // Fetch your decrypted secret key (implement this based on your storage)
    const secretKey = await getSecretKey(keyId);
    if (!secretKey) return false;
    
    // Validate timestamp (reject tokens older than 5 minutes)
    const currentTimestamp = Math.floor(Date.now() / 1000);
    const tokenTimestamp = parseInt(timestamp, 10);
    const maxAgeSeconds = 300; // 5 minutes (Depends on your needs)
    
    if (isNaN(tokenTimestamp) || currentTimestamp - tokenTimestamp > maxAgeSeconds) {
      return false; // Token expired or invalid timestamp
    }
    
    // Validate nonce (prevent replay attacks)
    if (usedNonces.has(nonce)) {
      return false; // Nonce already used
    }
    
    // Extract and sort URL parameters
    const urlObj = new URL(url);
    const params = Array.from(urlObj.searchParams.entries())
      .sort((a, b) => a[0].localeCompare(b[0]))
      .map(([k, v]) => `${k}=${v}`)
      .join('&');
    
    // Reconstruct signing payload
    const payload = `${params}&ts=${timestamp}&nonce=${nonce}`;
    
    // Calculate expected signature
    const expectedSignature = crypto
      .createHmac('sha256', secretKey)
      .update(payload)
      .digest('hex');
    
    // Timing-safe comparison
    const isValid = crypto.timingSafeEqual(
      Buffer.from(expectedSignature),
      Buffer.from(providedSignature)
    );
    
    // Store nonce if valid (with TTL in production)
    if (isValid) {
      usedNonces.add(nonce);
      // Clean up expired nonces periodically
      setTimeout(() => usedNonces.delete(nonce), maxAgeSeconds * 1000);
    }
    
    return isValid;
  } catch (error) {
    console.error('Token verification error:', error);
    return false;
  }
}
```

#### PHP Verification Example

```php
<?php
// Use Redis or database in production
$usedNonces = [];

function verifySignedToken($token, $url) {
    global $usedNonces;
    
    // Parse token
    $parts = explode('.', $token);
    if (count($parts) !== 5 || strpos($parts[0], 'v') !== 0) {
        return false;
    }
    
    $version = $parts[0];
    
    $keyId = str_replace('kid=', '', $parts[1]);
    $timestamp = str_replace('ts=', '', $parts[2]);
    $nonce = str_replace('nonce=', '', $parts[3]);
    $providedSignature = str_replace('sig=', '', $parts[4]);
    
    // Fetch your secret key
    $secretKey = getSecretKey($keyId);
    if (!$secretKey) return false;
    
    // Validate timestamp (reject tokens older than 5 minutes)
    $currentTimestamp = time();
    $tokenTimestamp = intval($timestamp);
    $maxAgeSeconds = 300; // 5 minutes (Depends on your needs)
    
    if ($currentTimestamp - $tokenTimestamp > $maxAgeSeconds) {
        return false; // Token expired
    }
    
    // Validate nonce (prevent replay attacks)
    if (in_array($nonce, $usedNonces)) {
        return false; // Nonce already used
    }
    
    // Extract and sort URL parameters
    $urlParts = parse_url($url);
    parse_str($urlParts['query'], $params);
    ksort($params);
    
    $paramString = http_build_query($params);
    
    // Reconstruct signing payload
    $payload = "$paramString&ts=$timestamp&nonce=$nonce";
    
    // Calculate expected signature
    $expectedSignature = hash_hmac('sha256', $payload, $secretKey);
    
    // Timing-safe comparison
    $isValid = hash_equals($expectedSignature, $providedSignature);
    
    // Store nonce if valid
    if ($isValid) {
        $usedNonces[] = $nonce;
        // Clean up expired nonces periodically in production
    }
    
    return $isValid;
}
?>
```

#### Python Verification Example

```python
import hmac
import hashlib
import time
from urllib.parse import urlparse, parse_qs, urlencode
from typing import Set

# Use Redis or database in production
used_nonces: Set[str] = set()

async def verify_signed_token(token: str, url: str) -> bool:
    try:
        # Parse token
        parts = token.split('.')
        if len(parts) != 5 or not parts[0].startswith('v'):
            return False
        
        version = parts[0]
        
        key_id = parts[1].replace('kid=', '')
        timestamp = parts[2].replace('ts=', '')
        nonce = parts[3].replace('nonce=', '')
        provided_signature = parts[4].replace('sig=', '')
        
        # Fetch your secret key
        secret_key = await get_secret_key(key_id)
        if not secret_key:
            return False
        
        # Validate timestamp (reject tokens older than 5 minutes)
        current_timestamp = int(time.time())
        token_timestamp = int(timestamp)
        max_age_seconds = 300  # 5 minutes (Depends on your needs)
        
        if current_timestamp - token_timestamp > max_age_seconds:
            return False  # Token expired
        
        # Validate nonce (prevent replay attacks)
        if nonce in used_nonces:
            return False  # Nonce already used
        
        # Extract and sort URL parameters
        parsed = urlparse(url)
        params = parse_qs(parsed.query)
        # Flatten single-value lists and sort
        flat_params = {k: v[0] if len(v) == 1 else v for k, v in params.items()}
        sorted_params = urlencode(sorted(flat_params.items()))
        
        # Reconstruct signing payload
        payload = f"{sorted_params}&ts={timestamp}&nonce={nonce}"
        
        # Calculate expected signature
        expected_signature = hmac.new(
            secret_key.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        
        # Timing-safe comparison
        is_valid = hmac.compare_digest(expected_signature, provided_signature)
        
        # Store nonce if valid
        if is_valid:
            used_nonces.add(nonce)
            # Clean up expired nonces periodically in production
        
        return is_valid
    except Exception as e:
        print(f"Token verification error: {e}")
        return False
```

### FAQ

<details>

<summary>Is X-Tyrads-Token required?</summary>

While not mandatory, it's **strongly recommended** for enhanced security. Contact the TyrAds team to enable it for your account.

</details>

<details>

<summary>How often should I rotate my security key?</summary>

It depends on you if you want to rotate after n number of days. Same can be communicated to Tyrads

</details>

<details>

<summary>Can the same token be used twice?</summary>

No. Each token contains a unique nonce and timestamp. You should track used nonces (with TTL matching your timestamp validation window) to reject duplicate requests. Reusing tokens indicates a potential replay attack.

</details>

<details>

<summary>What if my key is compromised?</summary>

Immediately contact the TyrAds,   to deactivate the compromised key and issue a new one.

</details>

{% hint style="info" %}
For security key setup or issues, please reach out to the TyrAds team directly.
{% endhint %}


# TyrAds Fraud Suite V2 (SDK)

To ensure optimal traffic integrity and maximize campaign perf, TyrAds employs a multi-layered security system for our SDK partners.

Fraud Suite v2 Documentation:

{% file src="/files/Dp9eWj3Hh8aD6CGGlwdc" %}

#### 1. The Two-Layer Defense

* Layer 1: User Risk Scoring (Proactive): An automated system that scores every user at the moment they enter the SDK. Using 200+ data sources (including device fingerprints, location, and multi-accounting patterns), it blocks "High Risk" users before they can engage with any offers.
* Layer 2: Anomaly Detection (Reactive): A machine-learning system that monitors in-game activity. If a user bypasses Layer 1 but exhibits abnormal behavior patterns, their progress is rejected in real-time.

#### 2. For Anomaly Detection Layer

Our system analyzes post-install event patterns. If a user’s behavior is flagged as non-human or anomalous, the system triggers an automatic rejection.

Standardized Lookback Rules:

* **14-Day Window**: All conversions are subject to a 14-day lookback window, aligning with industry MMP standards.
* **CPI Model**: If an anomaly is detected within 14 days, both the install and all associated events are retroactively rejected.
* **CPE Model:** The specific anomalous event is rejected, and the user is flagged to prevent all future payouts on that campaign.
* **Post-14 Days**: The initial install remains approved, but specific anomalous events are rejected and non-payable.

#### 2. Technical Integration (Postback Macros)

If you needed to be notified on the rejections to your platform, please do consult Tyrads team to setup a rejected type Postback URL  \[**especially for CPI campaigns where we retroactively reject the install together with the event and make the install non-payable as well]**

The following are the important macros for rejected type postback:

| Macros                | Description                             | Example or Expected Value |
| --------------------- | --------------------------------------- | ------------------------- |
| `{conversion_status}` | The state of conversion                 | `rejected`                |
| `{reject_reason}`     | The rejection reason for the conversion | `Anomoly%20Detection`     |
| `{conversion_id}`     | Unique ID of a specific conversion      | `2563391781`              |

Example of suggested rejected postback URL:

{% tabs %}
{% tab title="Rejected Postback Format Example" %}
[https://your-api-endpoint.com/postback?id={conversion\_id}\&conversion\_status={conversion\_status}\&reject\_reason={reject\_reason}](https://your-api-endpoint.com/postback?id={conversion_id}\&status={conversion_status}\&reason={reject_reason}) + all existing macros setup in Ad Unit that is required
{% endtab %}
{% endtabs %}

***

Rejected postback Integration Checklist

* [ ] Ingest rejected type postback in your system if needed
* [ ] Map rejections using `conversion_id`&#x20;

{% hint style="warning" %}
Please do not reward the user upon receiving the rejected type postback if implementation of rejected postback is required.
{% endhint %}


# SDK Integration Checklist

To ensure a seamless SDK integration and maximize performance, please review this checklist. It covers essential best practices, parameter mappings, and required feature utilization.

<table><thead><tr><th width="164.37890625">Feature/ Parameter</th><th>Checklist Question</th><th>Recommendation / Action</th><th>Explanation</th></tr></thead><tbody><tr><td>Initialization</td><td>When are you initializing our SDK in your app?</td><td>Initialize during app launch/open, preferably after Mobile Media Partner (MMP) initialization (if any).</td><td>We recommend initializing our SDK during app launch, ideally after MMP initialization (if any).</td></tr><tr><td>Media Source Data <strong>[required]</strong></td><td>Are you passing media source data to us?</td><td><a data-mention href="/pages/sQLb6rC5ziweGZOyKpz8">/pages/sQLb6rC5ziweGZOyKpz8</a> <a data-mention href="/pages/JEG6ij8mXRezOjgHjPOZ">/pages/JEG6ij8mXRezOjgHjPOZ</a> </td><td>Send media data of where you acquired the users to our system. We will use this in our systems to be able to segment the user base and provide media-source-specific rewards.</td></tr><tr><td>Postback Setup</td><td>Are the postback macros setup and working correctly as intended?</td><td>Ensure that postbacks are received correctly on your server.</td><td>To ensure postback data is passed correctly to your end for user rewards.</td></tr><tr><td><p></p><p>Currency Conversion and Ad Unit settings</p></td><td>Are the media asset and ad unit settings correct?</td><td>Ensure that currency conversion and user margins are set up correctly in the ad unit in the Solutions dashboard.</td><td>Ensures currency conversion and user margins are accurate during user rewards and payouts.</td></tr><tr><td><p></p><p>Decimals in rewards</p></td><td>Does your system/server/app accept decimals in the user reward currency?</td><td>Please inform the <strong>TyrAds integration team</strong> about this.</td><td>We have settings that can be enabled to round user rewards to whole numbers.</td></tr></tbody></table>


# Tyrads Whitelist IP Addresses

This section provides the IPv4 addresses for Tyrads publisher postback service for your whitelisting purposes.

### Tyrads Publisher Postback IP Addresses

**IPv4 Address:**

```
3.84.56.180 
```

```
34.227.70.236 
```

```
52.202.96.227 
```

For more question, please contact your TyrAds administrator or integration team.

Last Updated: June 09, 2026


# Media Source Data Mapping

If you are running user acquisition through an MMP (Mobile Measurement Partner) such as Appsflyer, Adjust, or Singular, use the table below to map the attribution fields from your MMP to our parameter

This ensures the media source data you pass to us is consistent with what your MMP reports, so we can segment and optimize correctly.

{% hint style="info" %}
Where multiple keys are listed (e.g. af\_siteid > site\_id. > af\_channel), they are in order of priority - use the first one that is available in your MMP payload.
{% endhint %}

| Tyrads SDK Parameter | Appsflyer Key                       | Adjust Field     | Singular Field           |
| -------------------- | ----------------------------------- | ---------------- | ------------------------ |
| `mediaSourceName`    | media\_source                       | network          | source                   |
| `mediaCampaignName`  | campaign                            | campaign         | pcn (Campaign Name)      |
| `mediaSourceId`      | campaign\_id                        | campaign\_id     | pcid (Campaign ID)       |
| `mediaSubSourceId`   | af\_siteid > site\_id > af\_channel | adgroup / source | psid (Publisher Site ID) |
| `incentivized`       | is\_incentivized > is\_paid         | -                | -                        |
| `mediaAdsetName`     | af\_adset > adset                   | -                | pscn (Sub Campaign Name) |
| `mediaAdsetId`       | adset\_id                           | -                | pscid (Sub Campaign ID)  |
| `mediaCreativeName`  | af\_ad                              | creative         | pcrn (Creative Name)     |
| `mediaCreativeId`    | ad\_id                              | creative\_id     | pcrid (Creative ID)      |
| `sub1`               | af\_sub1                            | -                | -                        |
| `sub2`               | af\_sub2                            | -                | -                        |
| `sub3`               | af\_sub3                            | -                | -                        |
| `sub4`               | af\_sub4                            | -                | -                        |
| `sub5`               | af\_sub5                            | -                | -                        |


# Advanced options


# SDK  Media Source Data

For media source data mapping with MMP, please kindly refer to

Send media data of where you acquired the users to our system, we will use this in our systems to be able to segment the user base and provide media source specific rewards.&#x20;

For more information on MMP media source data mapping, please kindly refer to this section: [Media Source Data Mapping](/getting-started/media-source-data-mapping)

{% hint style="info" %}
This is related to initialization of the SDK.&#x20;
{% endhint %}

<table><thead><tr><th width="223">Paramater</th><th width="120">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>mediaSourceName [<strong>Mandatory]</strong></td><td>string</td><td>Can be used to send the source name of where you got the user </td></tr><tr><td>mediaCampaignName</td><td>string</td><td>Can be used to send the campaign name of where you got the user</td></tr><tr><td>mediaSourceId</td><td>string</td><td>Can be used to send the source id of where you got the user</td></tr><tr><td>mediaSubSourceId</td><td>string</td><td>Can be used to send the Sub Source id of where you got the user</td></tr><tr><td>Incentivized</td><td>boolean</td><td>Can be used to send if the user acquisition was done via incent channels or non incent channels.</td></tr><tr><td>mediaAdsetName</td><td>string</td><td>Can be used to send the adset name of where you got the user</td></tr><tr><td>mediaAdsetId</td><td>string</td><td>Can be used to send the adset id of where you got the user</td></tr><tr><td>mediaCreativeName</td><td>string</td><td>Can be used to send the CreativeName of where you got the user</td></tr><tr><td>mediaCreativeId</td><td>string</td><td>Can be used to send the creativeId of where you got the user</td></tr><tr><td>sub1</td><td>string</td><td>Can use this to to store any type of data. <br><br>Currently only used to store data can't be received on the postback</td></tr><tr><td>sub2</td><td>string</td><td>Can use this to to store any type of data. <br><br>Currently only used to store data can't be received on the postback</td></tr><tr><td>sub3</td><td>string</td><td>Can use this to store any type of data. And can be sent back on the postback as well.<br><br><a data-mention href="/pages/wA6KNwNFL96U0Tpn5ZNv">/pages/wA6KNwNFL96U0Tpn5ZNv</a></td></tr><tr><td>sub4</td><td>string</td><td>Can use this to store any type of data. And can be sent back on the postback as well.<br><br><a data-mention href="/pages/wA6KNwNFL96U0Tpn5ZNv">/pages/wA6KNwNFL96U0Tpn5ZNv</a></td></tr><tr><td>sub5</td><td>string</td><td>Can use this to to store any type of data. <br><br>Currently only used to store data can't be received on the postback</td></tr></tbody></table>


# Sending User Segments / User Info

Sending user segments to our system will allow our system to be able to segment the userbase within the segments you use on your side. As well it will allow us to use this information to detect fraudulent users.&#x20;

{% hint style="info" %}
This is related to intialization of the SDK&#x20;
{% endhint %}

{% hint style="warning" %}
This is not required, but allows us to be able to indentify fraudulents user based on email/phone numbers.&#x20;
{% endhint %}

| Paramater       | Data Type   | Description                                                                                                                                                                                                                                                |
| --------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| userPhoneNumber | Integer     | <p>Can be used to identify the user to prevent fraud. <br><br>Format the + as  00, example: 0015555551234 for a US number</p>                                                                                                                              |
| userEmail       | email       | Can be used to identify the user to prevent fraud                                                                                                                                                                                                          |
| userGroup       | JSON string | <p>Segment identifier passed as a JSON string, <br><br><code>e.g. "{"promo\_affinity\_ratio":0.42,"dynamic\_payer\_segment":"NonPayer","activity\_segment":"Tier 3","seniority\_segment":"Tier 4","rewarded\_video\_watcher\_category":"High"}"</code></p> |


# Prerequisite

* Unity version 2021.3.45 or higher
* Android SDK 24 or higher using Google Play Services
* iOS version 12.0 or higher


# Installation

### Install External Dependency Manager for Unity

The SDK depends on External Dependency Manager for Unity (EDM4U) for automatic resolution of native Android/iOS dependencies (e.g., Google Play Integrity libraries).&#x20;

If EDM4U is not already present in your project, install it before building.&#x20;

#### Option A: Install via package manager&#x20;

1. Open `Edit` -> <kbd>`Project Settings`</kbd> -> <kbd>`Package Manager`</kbd>&#x20;
2. Add a new **Scoped Registry** (or edit the existing OpenUPM entry) -&#x20;
   * Name: **package.openupm.com**&#x20;
   * URL: \*\*<https://package.openupm.com**&#x20>;
   * Scope(s): **com.google.external-dependency-manager**&#x20;
3. Click Save or Apply&#x20;

#### Option B: Install via OpenUPM&#x20;

1. Install OpenUPM CLI (if not installed):\
   &#x20;`npm install -g openupm-cli`&#x20;
2. 2\. In your Unity project folder, run:\
   `openupm add com.google.external-dependency-manager`&#x20;

#### Option C: Install via Git URL&#x20;

1. Open **Package Manager**.&#x20;
2. Click on the **+** icon on the top left corner of the "**Package Manager**" screen&#x20;
3. Click on "**Install package from git url...**"&#x20;
4. Paste:\
   `https://github.com/googlesamples/unity-jar-resolver.git?path=upm`

### Install TyrAds Unity SDK

The **TyrAds Unity SDK** available from a Git URL. To install:

1. Open the ***Package Manager*** window in Unity, if it’s not already open.
2. Open the ***Add (+)*** menu in the Package Manager’s toolbar.
3. Select ***Install package from git URL*** from the install menu.
4. Enter a Git URL in the text box.&#x20;

   `https://github.com/tyrads-com/tyrads-unity-sdk-package.git`
5. Select \`***Install***\`.

If you want to check for updates and update **TyrAds Unity SDK** dependency to the latest version from the repository, click ***Update*** in the ***Package Manager*** window.

<figure><img src="/files/HYSU8gKKSepV2HY47CJD" alt=""><figcaption></figcaption></figure>

To explore how to use the TyrAds Unity SDK, import the Demo example from the package’s Samples section in the Unity Package Manager. To run a Demo scene, please add a valid credentials from our CRM.&#x20;


# SDK Integration

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

Integrating the TyrAds offerwall functionality into your application is a straightforward process that involves a few key steps. By following these integration steps, you can seamlessly incorporate the offerwall feature, enhancing user engagement and potentially generating additional revenue for your application.

{% hint style="success" %}

### SDK Initialization best practices:

* **Initiate early:** It's advisable to initialize the SDK promptly after your app launches to ensure that all Tyr SDK functionalities are accessible when needed.
* **Initiate authentication:** Login to the SDK with current user details immediately after your user signs up or signs in to the app to set the `userId`.
  {% endhint %}

For guidance on integrating TyrSDK - including proper initialization and offer display - see the example at `Sample -> Demo` .

{% content-ref url="/pages/C5oroS3PgljSCzwOiFHY" %}
[1. Scene setup](/unity/sdk-integration/1.-scene-setup)
{% endcontent-ref %}

{% content-ref url="/pages/ee4vv0lA2xdWlfF5Ez0F" %}
[2. Credentials setup](/unity/sdk-integration/2.-credentials-setup)
{% endcontent-ref %}

{% content-ref url="/pages/vkqc6mSx3kLE6MvR4FNW" %}
[3. User Login](/unity/sdk-integration/3.-user-login)
{% endcontent-ref %}

{% content-ref url="/pages/JoqyAJ76vQgUxOh0cWWC" %}
[4. Open Offerswall](/unity/sdk-integration/4.-open-offerswall)
{% endcontent-ref %}

{% content-ref url="/pages/DE8K1fJ6bfrZk1c9I6Aa" %}
[5. Configure SDK Initialization Wizard](/unity/sdk-integration/5.-configure-sdk-initialization-wizard)
{% endcontent-ref %}

{% content-ref url="/pages/LXFW8RaZTpFMjxSBxZGH" %}
[6. Change Language](/unity/sdk-integration/6.-change-language)
{% endcontent-ref %}

{% content-ref url="/pages/vVH7Qd9vmu0SSKixNsLm" %}
[7. Setup Required Android Permissions](/unity/sdk-integration/7.-setup-required-android-permissions)
{% endcontent-ref %}

{% content-ref url="/pages/XH10SeB3H0Z4abwHhgOZ" %}
[8. Obtaining Advertising ID's](/unity/sdk-integration/8.-obtaining-advertising-ids)
{% endcontent-ref %}


# 1. Scene setup

Add the **TyrSDKPlugin** prefab to your scene (ideally once to your initial or bootstrap scene) from:

```
Packages/com.tyrads.unity-sdk/Runtime/Resources/TyrAds/Prefabs/TyrSDKPlugin.prefab
```

This enables API access via `TyrSDKPlugin.Instance` in code.

### Event System Requirement

The SDK UI is built using Unity’s standard Event System (UGUI). All interactive elements (buttons, toggles, input fields, etc.) rely on an active EventSystem in the scene to function correctly.

Unity UI input is processed through the EventSystem and an associated input module (e.g. StandaloneInputModule or InputSystemUIInputModule). If no EventSystem is present, UI elements will not receive input events, which may appear as if the UI is frozen or unresponsive.&#x20;

#### When you need to take action

If your project:

* Uses a custom input system, or
* Does not include a default EventSystem in the scene,

you must ensure that an EventSystem is available when the SDK UI is active.&#x20;

#### How to fix

Add an EventSystem GameObject to the scene where the SDK prefab is used.

Steps:

1. Create a new GameObject
2. Add component: EventSystem
3. Add one of the input modules:
   * StandaloneInputModule (old input system)
   * InputSystemUIInputModule (new input system)

#### Important Notes

* Unity supports only one active EventSystem per scene
* Multiple EventSystem instances may cause undefined behavior or input issues
* The SDK does not automatically include an EventSystem to avoid conflicts with existing project setups


# 2. Credentials setup

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

To initializes the **TyrAds Unity SDK** you must provide the necessary credentials obtained from the TyrAds platform. These credentials allow your application to establish secure communication with the TyrAds' backend services. There are two supported approaches for setting up credentials: a Unity Editor–based approach and a code-based approach.

#### a. Unity Editor–based approach&#x20;

Once **TyrSDK** is imported, follow these steps to configure it in your project:

* **Open the Configuration Window**
  * Navigate to **TyrSDK > TyrSDK Settings** to access the **TyrSDK Settings** panel.
* **Enter Your Credentials**
  * **API Key:** A **32-character** hexadecimal string (Mandatory. Grabbed from TyrAds Dashboard).
  * **API Secret Key:** A **92-character** hexadecimal string(Mandatory. Grabbed from TyrAds Dashboard).
  * **Encryption Key:** A **32**-**character** hexadecimal string (Optional. Grabbed from TyrAds Dashboard).

<figure><img src="/files/QcnMZbcJWtqNrbchajqI" alt=""><figcaption></figcaption></figure>

#### b.  Code-based approach

You can initialize credentials programmatically. Credentials could be initialized by a call:

```csharp
SessionConfig sessionConfig = new(
                    apiKey: "TestApiKey",
                    apiSecret: "TestApiSecret",
                    encryptionKey: "testEncryptionKey");
InitConfig initConfig = new (sessionConfig);
TyrSDKPlugin.Instance.Init(initConfig);
```

`Init` method had to be called before calling `LoginUserAsunc` to ensure that your credentials are properly set before the login process begins.

`InitConfig` also accepts an optional `ScreenOrientationPreference` to lock the offerwall's screen orientation independently of your app's own orientation settings:

```
InitConfig initConfig = new (sessionConfig, ScreenOrientationPreference.Portrait);
TyrSDKPlugin.Instance.Init(initConfig);
```

Available values: `None` (default, follows Unity Player Settings), `AutoRotation`, `Portrait`, `Landscape`, `LandscapeLeft`, `LandscapeRight`.

**Notes**

If credentials are configured both in the Editor and via code, the programmatic initialization will override the Editor settings at runtime.

#### Using Different Credentials for Android and iOS&#x20;

In some projects, you may need to initialize the SDK with different credentials per platform (e.g., separate API keys for iOS and Android).

Editor-based configuration does not support platform-specific credentials, this type of configuration cannot be handled through the Settings Editor window.

To support platform-specific credentials, you must use the code-based initialization approach.

On the developer side, the application should detect the active platform at runtime and provide the correct credentials accordingly.

Below is a simple example demonstrating how to configure this:

```csharp
string apiKey = "DEFAULT_API_KEY";
string apiSecretv = "DEFAULT_API_SECRET";
string encryptionKey = "DEFAULT_ENCRYPTION_KEY";

#if UNITY_ANDROID
  apiKey = "ANDROID_API_KEY";
  apiSecretv = "ANDROID_API_SECRET";
  encryptionKey = "ANDROID_ENCRYPTION_KEY";
#elif UNITY_IOS
  apiKey = "IOS_API_KEY";
  apiSecretv = "IOS_API_SECRET";
  encryptionKey = "IOS_ENCRYPTION_KEY";
#endif

SessionConfig sessionConfig = new(
                    apiKey: "TestApiKey",
                    apiSecret: "TestApiSecret",
                    encryptionKey: "testEncryptionKey");
InitConfig initConfig = new (sessionConfig);
TyrSDKPlugin.Instance.Init(initConfig);
```


# 3. User Login

Upon initializing the SDK, the mandatory step is to log in the user. However, passing a user ID is optional and is only necessary when the publisher operates its own user system. This login process ensures that user interactions with the offerwall are accurately tracked and attributed within the application.

```csharp
LoginData loginData = new LoginData(userId: "userId"); //userID is optional
_ = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);

```

{% hint style="warning" %}

* If you do not provide a user ID, it will be generated automatically and stored in app storage. In that case, uninstalling the app will erase the ID and the user’s progress.
* **Preferred: supply a backend-controlled, stable user ID (or equivalent) so progress persists across reinstalls and device changes.**&#x20;
  {% endhint %}

To determine when initialization has completed, you can await the login operation and read the relevant data from the returned **LoginResult**:

<pre class="language-csharp"><code class="lang-csharp">LoginData loginData = new LoginData(userId: "userId");
LoginResult result = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);

if (result.IsSuccessful)
{
    //do anything what you want after successful init...
} else
{
    // Handle unsuccessful login.
<strong>    // For example, send result.ErrorCode and result.ErrorMessage
</strong>    // to your analytics service to gain more insight into what went wrong.
}
</code></pre>

If you don’t set a user ID in LoginUser, you can retrieve the generated user ID after successful initialization by calling the following method:

```csharp
var userId = TyrSDKPlugin.Instance.GetUserId();
```

**Handling Login Errors**

{% hint style="info" %}
We strongly recommend handling unsuccessful login attempts and recording the error details for troubleshooting purposes.

When a login request fails, the returned result contains the following properties:

* `ErrorCode` – an error code identifying the reason for the failure.
* `ErrorMessage` – a human-readable description of the error.

These values can be forwarded to your analytics and crash-reporting systems (for example, Firebase Analytics, Firebase Crashlytics, Sentry, etc.). This information can help you diagnose integration issues and provide more details when contacting support.
{% endhint %}

When `LoginUserAsync` fails, the returned `LoginResult.ErrorCode` (`LoginErrorCode`) tells you why:

```
LoginResult result = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);

if (!result.IsSuccessful)
{
    Debug.LogWarning($"{result.ErrorCode}: {result.ErrorMessage}");
}
```

`LoginErrorCode` values: `None`, `SdkNotInitialized`, `MissingLoginData`, `MissingCredentials`, `AlreadyInitialized`, `RequestFailed`, `SessionRegistrationFailed`, `NativePluginNotInitialized`, `NetworkError`, `Timeout`, `AccessDenied`, `ResponseParsingError`, `ServerError`.

On transient failures (`NetworkError`, `Timeout`, `ResponseParsingError`, `ServerError`) the SDK automatically retries the initialization request once after a short delay before returning a failed `LoginResult`. Credential/attestation rejections (`AccessDenied`) are never retried.

#### 3.1 Advanced Practices for personalized rewards

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

To maximize the value of our Tyr SDK please follow the advanced options for user login. This will allow us to personalize the rewards for the user event further and maximize the earnings for you as publisher.&#x20;

```csharp
var userInfo = new TyradsUserInfo(
    userPhoneNumber: "+1234567890",
    userEmail: "demo@example.com",
    userGroup: "{\"promo_affinity_ratio\": 0.42, \"dynamic_payer_segment\": \"NonPayer\", \"activity_segment\": \"Tier 3\", \"seniority_segment\": \"Tier 4\", \"rewarded_video_watcher_category\": \"High\"}"
);

var mediaSourceInfo = new TyradsMediaSourceInfo(
    mediaSourceName: "Facebook", //mandatory
    mediaCampaignName: "Summer Sale Campaign",
    mediaSourceId: "fb_123",
    mediaSubSourceId: "fb_sub_456",
    incentivized: true,
    mediaAdsetName: "Summer Sale Adset",
    mediaAdsetId: "adset_789",
    mediaCreativeName: "Summer Sale Creative",
    mediaCreativeId: "creative_101",
    sub1: "campaign_source",
    sub2: "ad_group",
    sub3: "creative_type",
    sub4: "placement",
    sub5: "custom_param"
);

var engagementInfo = new TyradsEngagementInfo(
    engagementId: 12345  // Unique identifier for tracking user engagement
);

LoginData loginData = new LoginData("userID", userInfo, mediaSourceInfo, engagementInfo);
LoginResult result = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);
```

[SDK  Media Source Data](/getting-started/advanced-options/sdk-media-source-data)<- For more information regarding the media source data details, please navigate this this page

[Sending User Segments / User Info](/getting-started/advanced-options/sending-user-segments-user-info) <- For more information regarding the userInfo and `userGroup` data, please navigate this this page

#### 3.2 User Age & Gender Requirement

Before users can participate in reward activities, the SDK requires their age and gender to comply with partner requirements and properly configure available campaigns. If this information has not been provided, the SDK will automatically display a User Information page when the user opens any SDK screen that requires reward eligibility. After the data is submitted, it is stored and the page will not appear again unless the SDK state is reset.

**Providing Age & Gender via API**

If your application already collects age and gender, you can provide this information directly to the SDK. In this case, the User Information page will not be shown, ensuring a smoother user experience without additional prompts.

```csharp
var userInfo = new TyradsUserInfo(
    userAge: 20,
    userGender: UserGender.Male
);

LoginData loginData = new LoginData("userID", userInfo);
LoginResult result = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);
```

Providing user information programmatically is recommended when the application already manages user profiles or collects demographic data during onboarding.

#### **3.3** Initialization & Authentication State

After the SDK completes its startup flow, it is important to clearly understand what “initialization” means in this context.

Although internally the SDK performs an initialization request, from a product and API perspective this step is effectively a user authentication (login) process. Once this flow completes successfully, the SDK is fully ready for use.

To allow developers to reliably verify this state, the SDK exposes a dedicated property that indicates whether the initialization/authentication process has finished successfully.

```csharp
if (TyrSDKPlugin.Instance.IsInitialized)
{
    // your logic there
}
```

{% hint style="info" %}
The SDK exposes an `Init(...)` method, but its purpose is often misunderstood is sometimes misunderstood and union with `IsInitialized`.&#x20;

`Init(...)` method does not initialize the SDK. Instead, this method is responsible for configuring the SDK with the required parameters that will later be used during the authentication phase (in `LoginUserAsync(...)` method).
{% endhint %}

**Key Notes**

* `IsInitialized` reflects both:
  * Successful SDK setup
  * Successful user authentication
* A `true` value guarantees that:
  * All required backend requests are completed
  * The SDK is in a valid, ready-to-use state
* A `false` value means:
  * Initialization/authentication is still in progress, or
  * The process has failed


# 4. Open Offerswall

Once the SDK is initialized, you can present the offerwall to the user by calling the appropriate method from the TyrAds SDK. This is done by creating an OffersRoutingData instance with a specific placementId and passing it to the ShowOffers method.

The placementId (for example, 123) defines the placement configured on the backend and determines which offerwall content will be shown.

```csharp
OffersRoutingData offersRoutingData = new OffersRoutingData(placementId: 123); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);
```

This call opens the offerwall, where users can interact with available offers, advertisements, or promotions and earn rewards or incentives based on their engagement.

#### 4.1 Deeplinking Routes

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well. Available routes and their usage:

* `TyradsDeepRoutes.Offers` - opens the Campaigns Page
* `TyradsDeepRoutes.ActiveOffers` - opens the Activated Campaigns Page
* `TyradsDeepRoutes.Offer` - opens the Campaign Details Page (requires campaignID)
* `TyradsDeepRoutes.Support` - opens the Campaign Tickets Page (requires campaignID)

```csharp
//Use TyradsDeepRoutes class to avoid typos
OffersRoutingData offersRoutingData = new OffersRoutingData(placementId: 345, TyradsDeepRoutes.Offers); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);

//Specify a route and campaignID
OffersRoutingData offersRoutingData = new OffersRoutingData(placementId: 231, TyradsDeepRoutes.Offer, campaignId: 111); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);
```

#### 4.2 Offerwall Lifecycle Events

`TyrSDKPlugin` exposes events so you can react to the offerwall's open/close lifecycle, for example to pause gameplay while it's shown or to resume it once the user is done.

```csharp
TyrSDKPlugin.Instance.OfferwallOpened += OnOfferwallOpened;
TyrSDKPlugin.Instance.OfferwallClosed += OnOfferwallClosed;
TyrSDKPlugin.Instance.OfferwallShowFailed += OnOfferwallShowFailed;

private void OnOfferwallOpened()
{
    // e.g. pause gameplay
}

private void OnOfferwallClosed()
{
    // e.g. resume gameplay
}

private void OnOfferwallShowFailed(OfferwallFailReason reason)
{
    // e.g. show a fallback UI; reason indicates why the offerwall could not be shown
}
```

`OfferwallFailReason` values: `Unknown`, `NotReady`, `InvalidConfiguration`, `NativePluginUnavailable`, `LoadError`.


# 5. Configure SDK Initialization Wizard

By default TyrAds SDK before open any offers page show initialization wizard, where user could read and accept TyrAds Privacy Policy, give acess to usege stats permit (only on Android) and provide information about age and gender. You able to disable presentation of the privacy policy and usege stats permit pages.&#x20;

To do that follow next steps:

* Navigate to **TyrSDK > TyrSDK Settings** to access the **TyrSDK Settings** panel.
* Switch to **Settings** tab.
* Switch toggles for 'Show Privacy Policy Page' and 'Show Usage Stats Permit Page'.

The same **Settings** tab also has a **Log Level** field (flags-based: `Verbose`, `Debug`, `Info`, `Warning`, `Error`)\
controlling which SDK log messages are written to the console, and an **Iframe Settings** section exposing the same `Screen Orientation Preference` described above as an editor-configurable default.\
Note that calling `Init(initConfig)` from code always supersedes this default at runtime — if you don't pass a `ScreenOrientationPreference` to `InitConfig`,\
it resets to "auto" rather than falling back to the Editor value, the same way code-based credentials override Editor-configured ones.

<figure><img src="/files/I807MHauF7guck72ISTA" alt=""><figcaption></figcaption></figure>


# 6. Change Language

Use the following to change the TyrAds SDK language and update its internal locale settings:

```csharp
TyrSDKPlugin.Instance.SetLanguage("en");
```

#### Parameters:

* `languageCode` (string): A string representing the desired language code (e.g., "en" for English, "es" for Spanish). This should be a valid ISO 639-1 language code. \
  Supported languages: English (`en`), German (`de`), Spanish (`es`), French (`fr`), Indonesian (`id`), Japanese (`ja`), Korean (`ko`), Chinese Simplified (`zh-Hans-CN`), Chinese Traditional (`zh-Hant-CN`, `zh-Hant-HK`, `zh-Hant-TW`).

  `LanguageCode` exposes named constants for most of these (e.g. `LanguageCode.English`, `LanguageCode.German`); the Chinese Traditional variants aren't exposed as constants yet and should be passed as raw strings (e.g. `SetLanguage("zh-Hant-TW")`).

#### Notes:

* By default, the TyrAds SDK uses the device’s system language.
* This method saves the selected language in shared preferences so it persists across sessions.
* Ensure your app and the TyrAds SDK support the provided language code; otherwise, English will be used.


# 7. Setup Required Android Permissions

To ensure proper SDK functionality, configure your main AndroidManifest.xml at:

```
Assets/Plugins/Android/AndroidManifest.xml
```

&#x20;You can either:

* Copy the reference manifest as your main file from `Packages/com.tyrads.unity-sdk/Runtime/AndroidManifestReference/AndroidManifest.xml`, or
* Add the following permissions manually to your existing manifest:

```xml
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
```

**Important Notes:**

* **Placement:** Add the permissions **inside the `<manifest>` tag but outside the `<application>` tag**.
* **Manual Integration:** These permissions are **not added automatically** due to a conflict with main `AndroidManifest` Make sure to insert them manually.

**Minimum SDK Requirements:**

* `PACKAGE_USAGE_STATS` may require your app to target **API level 30+**.


# 8. Obtaining Advertising ID's

**Android 12+**

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the `AndroidManifest.xml` file.

Navigate to the `Assets/Plugins/Android/AndroidManifest.xml` inside your project, locate the `AndroidManifest.xml` file and add the following line just before the `<application>`.

```
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
```

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248).

**iOS 14+**

`NSUserTrackingUsageDescription` should be added to `Info.plist` file like

```
<key>NSUserTrackingUsageDescription</key><string>
```

The SDK includes a Unity build post-process that adds this to the build’s `Info.plist` .&#x20;

Request IDFA Permission&#x20;

Tyrads SDK can work with or without the IDFA permission on iOS 14+. If no permission is granted in the ATT popup, the SDK will serve non personalized offers to the user. In that scenario the conversion is expected to be lower. Offerwall integrations perform better compared to when no IDFA permission is given. Our recommendation is that you should ask for IDFA usage permission prior to TyrAds SDK initialization.<br>


# Migration guide to v3.1.0 or newer

## Migrating from TyrAds SDK v3.0 (.unitypackage) to v3.1.0 or newer (UPM)

This guide walks you through upgrading a project that previously used the v3.0 .unitypackage to the new v3.1.0 or newer package distributed via the Unity Package Manager (UPM).

Before you start

* Commit or back up your project.
* Close running play sessions and save all open scenes.

***

### 1) Remove the old v3.0 installation

The .unitypackage installed files directly under your Assets/ folder. To avoid duplicate symbols and GUID conflicts, remove the old content completely.

Default folder path:

```
Assets/Plugins/TyrAdsSDK/. //Path could be if differ if your team have moved sdk
```

***

### 2) Install latests (v3.1.0 or newer) package via the Unity Package Manager (UPM)

Follow the steps from [Installation](/unity/installation) page.

After installation, you should see TyrAds Unity SDK under Packages/ in the Project window.

***

### 3) Verify & refresh scene references

Because the UPM package provides new prefab and script GUIDs, references from the old .unitypackage may be missing. Open your main scenes and fix any missing references.

#### 3.1 Main SDK object on the scene

* Look for your previous TyrSDKPlugin object.
* If the component shows Missing (Mono Script) or a broken reference:
  1. Remove the broken component/prefab instance.
  2. Locate the new prefab in the package folder

     <kbd>Packages/com.tyrads.unity-sdk/Runtime/Prefabs/TyrSDKPlugin.prefab</kbd>.
  3. Drag the new prefab into your scene.
  4. Reapply any scene-specific settings you previously had.

***

### 4) Reapply configuration (only if you used the SDK editor window)

* If you previously configured the SDK via its Editor Window (e.g., entering app ids/keys, toggles, or project-wide settings):
  * Open the new TyrAds Settings&#x20;

    **TyrSDK > TyrSDK Settings**.
  * Re-enter your configuration values as before.
* If your configuration is set programmatically (in code):
  * No extra steps needed. Your code-based configuration should continue to work after you fix script/component references.

***

### 5) Clean up and validate

1. Save all modified scenes.
2. Enter Play Mode and validate:
   * Initialization logs appear without errors.
   * The premium widget renders and behaves as expected.
   * Ads/placements load and show as before (in appropriate test/dev environments).

***

### Troubleshooting

* Duplicate class/namespace or redefinition errors:

  You still have old .cs files under Assets/. Recheck step 1 and remove any leftovers.
* Missing script on a prefab after install:

  Replace the instance with the new prefab from the UPM package (see step 3).
* Editor window/menu not found:

  Ensure v3.1.0 or newer is installed under Packages/ and re-open Unity if needed. Some editor menus appear after a domain reload.

***

### Quick Checklist

* Old TyrAds folders removed from Assets/ (default or any custom locations)
* TyrAds SDK v3.1.0 or newer installed via UPM
* Main SDK scene object replaced/verified
* Premium widget prefab replaced/verified
* Configurations re-applied (only if previously set in editor)
* Play Mode sanity test passed


# Prerequisite

* Min Android SDK 24 or higher using Google Play Services


# Installation

Step 1. Add the JitPack repository to your build file&#x20;

Add it in your root build.gradle at the end of repositories:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            mavenCentral()
            maven { url 'https://jitpack.io' }
        }
    } 
```

{% endtab %}

{% tab title="Groovy" %}

```groovy

dependencyResolutionManagement {
		repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
		repositories {
			mavenCentral()
			maven { url 'https://jitpack.io' }
		}
	} 

```

{% endtab %}
{% endtabs %}

Step 2. Add the dependency

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
    dependencies {
        implementation ("com.github.tyrads-com:tyrads-sdk-android:LATEST_VERSION") // replace LATEST_VERSION with  1.1.0 or the latest stable version	}
```

{% endtab %}

{% tab title="Groovy" %}

```groovy
dependencies {
        implementation 'com.github.tyrads-com:tyrads-sdk-android:LATEST_VERSION'  // replace LATEST_VERSION with  1.1.0 or the latest stable version
	}1.1.0 or the latest stable version	}
```

{% endtab %}
{% endtabs %}


# Initialization

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

Integrating the Tyrads offerwall functionality into your application is a straightforward process that involves a few key steps. By following these integration steps, you can seamlessly incorporate the offerwall feature, enhancing user engagement and potentially generating revenue for your application.

### 1. Initialization

{% hint style="success" %}

### SDK Initialization best practices:

* **Initiate early:** It's advisable to initialize the SDK promptly after your app launches to ensure that all Tyr SDK functionalities are accessible when needed.
* **Initiate post-app authentication:** Re-initiate the SDK with current user details immediately after your user signs up or signs in to the app to update the `userId`.
* **Initiate periodically:** To optimize user experience, we strongly suggest invoking this method each time your app is brought to the forefront. This shouldn't impact your app's performance noticeably.
  {% endhint %}

This step initializes the Tyrads SDK within your application. You need to provide the API key and API secret obtained from the Tyrads platform. This allows your app to communicate securely with Tyrads' servers.

| Parameter         | Type                    | Required | Description                                                                                                                     |
| ----------------- | ----------------------- | :------: | ------------------------------------------------------------------------------------------------------------------------------- |
| `context`         | `ApplicationContext`    |  **Yes** | The application or activity context.                                                                                            |
| `apiKey`          | `String`                |  **Yes** | Your unique publisher identifier obtained from the Tyrads Dashboard.                                                            |
| `apiSecret`       | `String`                |  **Yes** | Your publisher secret key used for secure server communication.                                                                 |
| `encKey`          | `String`                |    No    | **Encryption Key**: If provided, the SDK encrypts sensitive data during transmission. Recommended for high-security apps.       |
| `placementId`     | `String`                |    No    | Used to differentiate between different  coins and use as per your selection within your app.                                   |
| `userInfo`        | `TyradsUserInfo`        |    No    | Metadata about the user (email, phone, user group) used for segmenting and personalizing offers.                                |
| `mediaSourceInfo` | `TyradsMediaSourceInfo` |    No    | **Attribution Data**: Details about where the user came from (e.g., Facebook, Organic). Helps in tracking campaign performance. |
| `config`          | `TyradsConfig`          |    No    | Android Only: settings for Android behavior, such as `skipInitialPages` to bypass privacy/permission screens.                   |
| `launchMode`      | `TyradsLaunchMode`      |    No    | Internal configuration for how the offerwall container is launched.                                                             |

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
CoroutineScope(Dispatchers.Main).launch {
    try {
        Tyrads.getInstance().init(
            context = applicationContext,
            apiKey = "YOUR_API_KEY",
            apiSecret = "YOUR_API_SECRET",
            encryptionKey = "YOUR_ENCRYPTION_KEY", // Optional
            engagementId = "YOUR_ENGAGEMENT_ID",   // Optional
            placementId = "YOUR_PLACEMENT_ID",     // Optional
            config = TyradsConfig(
                skipInitialPages = true // Bypasses consent screens
            ),
            debugMode = false // Set to true to view SDK console logs
        )
        // SDK initialized successfully
    } catch (e: Exception) {
        // Handle initialization failure
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
import com.tyrads.sdk.Tyrads;
import com.tyrads.sdk.TyradsCallback;
import com.tyrads.sdk.acmo.modules.input_models.TyradsConfig;

Tyrads.getInstance().init(
    context,
    "YOUR_API_KEY",
    "YOUR_API_SECRET",
    "YOUR_ENCRYPTION_KEY", // Optional (pass null if not needed)
    "YOUR_ENGAGEMENT_ID",   // Optional (pass null if not needed)
    "YOUR_PLACEMENT_ID",     // Optional (pass null if not needed)
    new TyradsConfig(true),  // skipInitialPages = true
    false,                   // debugMode = false
    new TyradsCallback() {
        @Override
        public void onSuccess() {
            // SDK initialized successfully
        }

        @Override
        public void onFailure(String error) {
            // Handle initialization failure
        }
    }
);
```

{% endtab %}
{% endtabs %}

`encryptionKey`: This would be used for encrypting data transmitted from the SDK. If not provided, data will be transmitted plain form.

`engagementId`: Optional engagement identifier to associate SDK activity with specific user engagements or campaigns.

`placementId`: Used to differentiate between different  coins and use as per your selection within your app.

`config`: (New) Configuration object (`TyradsConfig`) to customize SDK behavior. For example, `skipInitialPages` a Boolean (true or false) can be set dynamically. The `skipInitialPages` option in the `TyradsConfig` allows your app to bypass certain introductory pages during SDK initialization. When set to `true`, the SDK will **skip the Privacy and Terms & Conditions page as well as the Usage Permission page**, allowing users to enter directly into the main app experience without having to manually navigate through these consent or informational screens.

### 1.1 Advanced Practices for initialization for personalized rewards

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

To maximize the value of our Tyr SDK please follow the advanced options for initialization. This will allow us to personalize the rewards for the user event further and maximize the earnings for you as publisher.&#x20;

> \[!NOTE] Unassigned fields in `TyradsMediaSourceInfo` or `TyradsUserInfo` default to `null` automatically. Omit fields you do not require; there is no need to set them manually.

**Attributes Table**

| Data Model                | Parameter           | Type    | Description / Formatting                                                          |
| ------------------------- | ------------------- | ------- | --------------------------------------------------------------------------------- |
| **TyradsUserInfo**        | `email`             | String  | User's email address                                                              |
|                           | `phoneNumber`       | String  | User's phone number. Prefix `+` must be replaced with `00` (e.g. `0015555551234`) |
|                           | `userGroup`         | String  | Segment identifier (e.g. `"High purchase user"`)                                  |
|                           | `age`               | Int     | User's age                                                                        |
|                           | `gender`            | Int     | User's gender                                                                     |
| **TyradsMediaSourceInfo** | `mediaSourceName`   | String  | Platform of acquisition (e.g. `"Facebook"`, `"Google"`)                           |
|                           | `mediaCampaignName` | String  | Associated ad campaign name                                                       |
|                           | `mediaSourceId`     | String  | Unique ID representing the media source                                           |
|                           | `mediaSubSourceId`  | String  | Sub-source ID                                                                     |
|                           | `incentivized`      | Boolean | If the acquisition was via incentivized networks                                  |
|                           | `mediaAdsetName`    | String  | Acquisition ad set name                                                           |
|                           | `mediaAdsetId`      | String  | Acquisition ad set ID                                                             |
|                           | `mediaCreativeName` | String  | Acquisition ad creative asset name                                                |
|                           | `mediaCreativeId`   | String  | Acquisition ad creative asset ID                                                  |
|                           | `sub1` to `sub5`    | String  | Custom parameters for publisher tracking                                          |

**⚠️ Rule for Metadata Binding**

Always call `setMediaSourceInfo` and `setUserInfo` **immediately prior** to calling `init` or `loginUser` to guarantee that sessions are tracked with valid acquisition data.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import com.tyrads.sdk.Tyrads
import com.tyrads.sdk.TyradsUserInfo
import com.tyrads.sdk.TyradsMediaSourceInfo
import com.tyrads.sdk.acmo.modules.input_models.TyradsConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

CoroutineScope(Dispatchers.Main).launch {
    // 1. Prepare User and Media Source data
    val userInfo = TyradsUserInfo(
        email = "example@tyrads.com",
        phoneNumber = "87653211223",
        userGroup = "High purchase user"
    )
    val mediaSourceInfo = TyradsMediaSourceInfo(
        mediaSourceName = "Facebook",
        mediaCampaignName = "Summer Sale",
        mediaSourceId = "123",
        mediaSubSourceId = "A1",
        incentivized = true,
        mediaAdsetName = "AdSet1",
        mediaAdsetId = "AS123",
        mediaCreativeName = "CreativeBanner",
        mediaCreativeId = "CB123",
        sub1 = "user123",
        sub2 = "app_launch"
    )

    // 2. Set details prior to init
    Tyrads.getInstance().setMediaSourceInfo(mediaSourceInfo)
    Tyrads.getInstance().setUserInfo(userInfo)

    // 3. Initialize SDK
    Tyrads.getInstance().init(
        context = applicationContext,
        apiKey = "YOUR_API_KEY",
        apiSecret = "YOUR_API_SECRET",
        encryptionKey = "YOUR_ENCRYPTION_KEY",
        engagementId = "YOUR_ENGAGEMENT_ID",
        config = TyradsConfig(skipInitialPages = true)
    )
}
```

{% endtab %}

{% tab title="Java" %}

```java
import com.tyrads.sdk.Tyrads;
import com.tyrads.sdk.TyradsCallback;
import com.tyrads.sdk.TyradsUserInfo;
import com.tyrads.sdk.TyradsMediaSourceInfo;
import com.tyrads.sdk.acmo.modules.input_models.TyradsConfig;

// 1. Prepare structures
TyradsUserInfo userInfo = new TyradsUserInfo(
    "example@tyrads.com",
    "987653211223",
    "High purchase user",
    null, // age
    null  // gender
);

TyradsMediaSourceInfo mediaSourceInfo = new TyradsMediaSourceInfo(
    "Facebook",
    "Summer Sale",
    "123",
    "A1",
    true,
    "AdSet1",
    "AS123",
    "CreativeBanner",
    "CB123",
    "user123",
    "app_launch",
    null, // sub3
    null, // sub4
    null  // sub5
);

// 2. Set details prior to init
Tyrads.getInstance().setMediaSourceInfo(mediaSourceInfo);
Tyrads.getInstance().setUserInfo(userInfo);

// 3. Initialize SDK
Tyrads.getInstance().init(
    context,
    "YOUR_API_KEY",
    "YOUR_API_SECRET",
    "YOUR_ENCRYPTION_KEY",
    "YOUR_ENGAGEMENT_ID",
    null, // placementId
    new TyradsConfig(true),
    false,
    new TyradsCallback() {
        @Override
        public void onSuccess() {
            // SDK initialized
        }

        @Override
        public void onFailure(String error) {
            // Init failed
        }
    }
);
```

{% endtab %}
{% endtabs %}

[SDK  Media Source Data](/getting-started/advanced-options/sdk-media-source-data)

[Sending User Segments / User Info](/getting-started/advanced-options/sending-user-segments-user-info)

### 2. User Login

Upon initializing the SDK, the mandatory step is to log in the user. However, passing a user ID is optional and is only necessary when the publisher operates its own user system. This login process ensures that user interactions with the offerwall are accurately tracked and attributed within the application.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import com.tyrads.sdk.Tyrads
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

CoroutineScope(Dispatchers.Main).launch {
    // Pass custom User ID (Recommended) or omit/null for device ID tracking
    val isSuccess = Tyrads.getInstance().loginUser(userID = "YOUR_CUSTOM_USER_ID")
    if (isSuccess) {
        // Login complete
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
Timport com.tyrads.sdk.Tyrads;
import com.tyrads.sdk.TyradsLoginCallback;

Tyrads.getInstance().loginUser("YOUR_CUSTOM_USER_ID", new TyradsLoginCallback() {
    @Override
    public void onSuccess(boolean isNewUser) {
        // Login complete. isNewUser indicates if this profile was just created
    }

    @Override
    public void onFailure(String error) {
        // Handle login failure
    }
});
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
The generated user ID from the SDK is based on the device identifier (GAID/OAID/IDFA)

* If your app user resets the device identifier, your user will lose the progress data
* If the SDK can't access the device identifier, it will generate its own device identifier and store it in the app storage. If this is the case, your app user will lose the progress data when the user uninstalls the app
* **If you send us your userId within userId field from your backend we will save this and even if the user changes their device ID we will keep their progress.**&#x20;
  {% endhint %}

### 3. Show Offerwall&#x20;

Once the SDK is initialized and the user is logged in (if applicable), you can display the offerwall to the user. This typically involves calling a function provided by the Tyrads SDK, such as showOffers. The offerwall is where users can engage with various offers, advertisements, or promotions provided by Tyrads, potentially earning rewards or incentives in the process.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import com.tyrads.sdk.Tyrads
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

CoroutineScope(Dispatchers.Main).launch {
    // Launches full offerwall overlay
    Tyrads.getInstance().showOffers(
        route = null,      // Optional deep link route
        campaignID = null  // Optional campaign ID
    )
}
```

{% endtab %}

{% tab title="Java" %}

```java
import com.tyrads.sdk.Tyrads;
import com.tyrads.sdk.TyradsCallback;

Tyrads.getInstance().showOffers(
    null, // route
    null, // campaignID
    new TyradsCallback() {
        @Override
        public void onSuccess() {
            // Offerwall shown successfully
        }

        @Override
        public void onFailure(String error) {
            // Failed to launch offerwall
        }
    }
);
```

{% endtab %}
{% endtabs %}


# Deeplinking Routes

**NOTE**: **Min SDK version required: v1.1.8**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active offers` - opens the Activated Campaigns Page
* offers/\[id]- opens the Campaign Details Page (requires campaignID)
* `support` - opens the Campaign Tickets Page (requires campaignID)

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.getInstance().showOffers();

// Explicitly specifying the Campaigns Page
Tyrads.getInstance().showOffers(route: "offers");

// Activated Campaigns Page
Tyrads.getInstance().showOffers(route: "active-offers");

// Campaign Details Page (requires campaignID)
Tyrads.getInstance().showOffers(route: "offer", campaignID: "your_campaign_id_here");

// Campaign Tickets Page (requires campaignID)
Tyrads.getInstance().showOffers(route: "support", campaignID: "your_campaign_id_here");
```

{% endtab %}

{% tab title="Java" %}

```java
// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.getInstance().showOffers(
    null,
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Explicitly specifying the Campaigns Page
Tyrads.getInstance().showOffers(
    route: "offers",
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Activated Campaigns Page
Tyrads.getInstance().showOffers(
    route: "active-offers",
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Campaign Details Page (requires campaignID)
Tyrads.getInstance().showOffers(
    route: "offer",
    campaignID: "your_campaign_id_here",
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Campaign Tickets Page (requires campaignID)
Tyrads.getInstance().showOffers(
    route: "support",
    campaignID: "your_campaign_id_here",
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);
```

{% endtab %}
{% endtabs %}


# Premium Offers

### TopPremiumOffers Composable Function

#### Overview

The `TopPremiumOffers` composable function is designed to display top premium offers within the application. It utilizes the `TopOffers` composable to render the offers with specific settings.

#### Parameters:

* The `context` parameter is required and should be the context of the widget that will display the top offers widget.
* The `widgetStyle` parameter is used to choose the style of the widget. The default style is `PremiumWidgetStyles.LIST`, which displays the offers in a list. Other available style is `PremiumWidgetStyles.SLIDER_CARDS`, which displays the offers in a slider.

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p> Slider Cards</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>List View </p></figcaption></figure>

Return Value:

* `Widget`: A Composable `Widget` that can be embedded in your application's UI.

#### Usage

To use this composable, you can call it through the `Tyrads` instance like this:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
// Kotlin (Direct Jetpack Compose)
import androidx.compose.runtime.Composable
import com.tyrads.sdk.Tyrads

@Composable
fun MyCustomLayout() {
    // Renders the Tyrads Premium Offer widget natively
    Tyrads.getInstance().TopPremiumOffers(
        widgetStyle = Tyrads.PremiumWidgetStyles.LIST // Or Tyrads.PremiumWidgetStyles.SLIDER_CARDS
    )
}
```

{% endtab %}

{% tab title="Java" %}

```java
// Java Implementation (Instantiating dynamically via TyradsViewHelper)
import android.os.Bundle;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;
import com.tyrads.sdk.acmo.helpers.TyradsViewHelper;
import com.tyrads.sdk.acmo.modules.premium_widgets.TopPremiumOffersView;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LinearLayout container = findViewById(R.id.widget_container);

        // Dynamically instantiate the view using the built-in helper
        TopPremiumOffersView premiumOffersView = TyradsViewHelper.createTopPremiumOffersView(
            this,                 // Context
            true,                 // showMore
            false,                // showMyOffers
            false,                // showMyOffersEmptyView
            1                     // style (0 = SLIDER_CARDS, 1 = LIST)
        );

        container.addView(premiumOffersView);
    }
}
```

{% endtab %}

{% tab title="XML" %}

```xml
<!-- XML Layout Integration (Available for both Kotlin & Java) -->
<com.tyrads.sdk.acmo.modules.premium_widgets.TopPremiumOffersView
    android:id="@+id/premium_offers_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:showMore="true"
    app:showMyOffers="false"
    app:showMyOffersEmptyView="false"
    app:style="1" /> <!-- 0 = SLIDER_CARDS, 1 = LIST -->
```

{% endtab %}
{% endtabs %}


# changeLanguage

This asynchronous method allows you to change the language used by the Tyrads SDK. It updates the SDK's internal locale settings.

```dart
Tyrads.getInstance().changeLanguage("en");
```

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.
* `supported Languages`: English (en), Spanish (es), Indonesian (id), Japanese (ja), Korean (ko) and Chinese (China, Simplified) (zh-Hans-CN)

#### Usage Example:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
Button(
  onClick = {
    CoroutineScope(Dispatchers.Main).launch {
      Tyrads.getInstance().changeLanguage('es'); // Change to Spanish
    }
  }
) {
  Text(text = "Change Language")
},
```

{% endtab %}

{% tab title="Java" %}

```java
private Button button;
import com.tyrads.sdk.TyradsCallback;

button.setOnClickListener(
    v -> Tyrads.getInstance().changeLanguage(
            "id",
            new TyradsCallback {
                @Override
                fun onSuccess() {
                    Log.i("Tyrads", "Language changed successfully")
                }
                
                @Override
                fun onFailure(error: String) {
                    Log.e("Tyrads", "Failed to change language: $error")
                }
            }
        )
);
```

{% endtab %}
{% endtabs %}

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.


# Obtaining Advertising ID's

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the AndroidManifest.xml file.

Navigate to the `android/app/src/main` directory inside your project's root, locate the AndroidManifest.xml file and add the following line just before the `<application>`.

```
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
```

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248)


# Prerequisite

* Android SDK 24 or higher using Google Play Services
* iOS version 11.0 or higher
* Flutter version 1.20.0 or higher
* Dart SDK version 2.12.0 or higher
* CocoaPods version 1.10.0 or higher


# Installation

Just open the terminal with project root working and type below command

```bash
flutter pub add tyrads_sdk
```

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FjxRWBSTcObUX1TCoTG61%2Fuploads%2F7Ijr9hVMl6oQnS9cob6i%2Fimage.png?alt=media&#x26;token=0f07cf11-6de6-4eb9-9039-052954e8bdf6" alt=""><figcaption></figcaption></figure>


# Initialization

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

Integrating the Tyrads offerwall functionality into your application is a straightforward process that involves a few key steps. By following these integration steps, you can seamlessly incorporate the offerwall feature, enhancing user engagement and potentially generating revenue for your application.

### 1. Initialization

Initialization should occur as early as possible in your app's lifecycle (e.g., in `main()` or your initial landing page).

> \[!IMPORTANT] **Mandatory Navigator Key**: You must now provide a `GlobalKey<NavigatorState>` during initialization. This allows the SDK to manage overlays and navigation without requiring you to pass a `BuildContext` manually.

{% hint style="success" %}

### SDK Initialization best practices:

* **Initiate early:** It's advisable to initialize the SDK promptly after your app launches to ensure that all Tyr SDK functionalities are accessible when needed.
* **Initiate post-app authentication:** Re-initiate the SDK with current user details immediately after your user signs up or signs in to the app to update the `userId`.
* **Initiate periodically:** To optimize user experience, we strongly suggest invoking this method each time your app is brought to the forefront. This shouldn't impact your app's performance noticeably.
  {% endhint %}

This step initializes the Tyrads SDK within your application. You need to provide the API key and API secret obtained from the Tyrads platform. This allows your app to communicate securely with Tyrads' servers.

#### Basic Initialization

```dart
// 1. Create a GlobalKey in your main application state or global scope
final GlobalKey<NavigatorState> hostNavigatorKey = GlobalKey<NavigatorState>();

// 2. Assign it to your MaterialApp
MaterialApp(
  navigatorKey: hostNavigatorKey,
  // ... rest of your app
);

// 3. Initialize the SDK
await Tyrads.instance.init(
  navigatorKey: hostNavigatorKey, // Mandatory
  apiKey: "YOUR_API_KEY",
  apiSecret: "YOUR_API_SECRET",
);
```

#### Advanced Initialization (Personalized Rewards)

To maximize earnings and segment users, you can provide advanced user and media source information:

```dart
await Tyrads.instance.init(
  navigatorKey: hostNavigatorKey,
  apiKey: "YOUR_API_KEY",
  apiSecret: "YOUR_API_SECRET",
  encKey: "YOUR_ENCRYPTION_KEY", // Optional: Encrypts transmitted data
  userInfo: TyradsUserInfo(
    email: "user@example.com",
    userGroup: "High purchasing user",
    age: 28,
    gender: 1, // Male
  ),
  mediaSourceInfo: TyradsMediaSourceInfo(
    mediaSourceName: "Facebook",
    mediaCampaignName: "Summer2023Promo",
    mediaSourceId: "FB001",
    mediaSubSourceId: "FB001_Stories",
    incentivized: false,
    mediaAdsetName: "YoungAdults25-34",
    mediaAdsetId: "AD001",
    mediaCreativeName: "SummerSale_Video",
    mediaCreativeId: "CR001",
    sub1: "ReferralCode123",
    sub2: "OrganicInstall",
    sub3: "HighValueUser",
    sub4: "FirstTimeUser",
    sub5: "iOSDevice",
  ),
  config: TyradsConfig(
    skipInitialPages: true, // Only applied when running on Android
  ),
);
```

***

#### 1.1 Initialization Parameter Reference

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

The `init` method accepts several parameters to configure the SDK and enhance user attribution.

| Parameter         | Type                        | Required | Description                                                                                                                     |
| ----------------- | --------------------------- | :------: | ------------------------------------------------------------------------------------------------------------------------------- |
| `navigatorKey`    | `GlobalKey<NavigatorState>` |  **Yes** | The anchor for all SDK UI. Must be the same key assigned to your `MaterialApp`.                                                 |
| `apiKey`          | `String`                    |  **Yes** | Your unique publisher identifier obtained from the Tyrads Dashboard.                                                            |
| `apiSecret`       | `String`                    |  **Yes** | Your publisher secret key used for secure server communication.                                                                 |
| `encKey`          | `String`                    |    No    | **Encryption Key**: If provided, the SDK encrypts sensitive data during transmission. Recommended for high-security apps.       |
| `placementId`     | `String`                    |    No    | Used to differentiate between different  coins and use as per your selection within your app.                                   |
| `userInfo`        | `TyradsUserInfo`            |    No    | Metadata about the user (email, phone, user group) used for segmenting and personalizing offers.                                |
| `mediaSourceInfo` | `TyradsMediaSourceInfo`     |    No    | **Attribution Data**: Details about where the user came from (e.g., Facebook, Organic). Helps in tracking campaign performance. |
| `config`          | `TyradsConfig`              |    No    | Android Only: settings for Android behavior, such as `skipInitialPages` to bypass privacy/permission screens.                   |
| `launchMode`      | `TyradsLaunchMode`          |    No    | Internal configuration for how the offerwall container is launched.                                                             |

***

#### Detailed Objects

**TyradsUserInfo**

Used to provide context about the current user for better offer matching and demographic targeting.

* **`email`**: User's email address.
* **`phoneNumber`**: User's contact number.
* **`userGroup`**: A custom string to categorize users (e.g., "VIP", "High purchasing user").
* **`age`**: The user's age (e.g., `25`).
* **`gender`**: The user's gender represented as an integer (e.g., `1` for Male, `2` for Female).

**TyradsMediaSourceInfo**

Essential for publishers who want to track the source of their users.

* `mediaSourceName`: The platform name (e.g., "GoogleAdWords", "Facebook").
* `mediaCampaignName`: The specific marketing campaign name.
* `mediaCreativeId`: The ID of the specific ad creative the user interacted with.
* `sub1` through `sub5`: Custom slots for any additional tracking parameters you require.

[SDK  Media Source Data](/getting-started/advanced-options/sdk-media-source-data)

[Sending User Segments / User Info](/getting-started/advanced-options/sending-user-segments-user-info)

***

### 2. User Authentication

Logging in the user is mandatory. While providing a `userID` is optional, we **strongly recommend** using your own internal User ID to ensure progress is saved across device changes.

```dart
// userID is your internal app identifier for the user
await Tyrads.instance.loginUser(userID: "my_unique_user_123");
```

{% hint style="warning" %}
The generated user ID from the SDK is based on the device identifier (GAID/OAID/IDFA)

* If your app user resets the device identifier, your user will lose the progress data
* If the SDK can't access the device identifier, it will generate its own device identifier and store it in the app storage. If this is the case, your app user will lose the progress data when the user uninstalls the app
* **If you send us your userId within userId field from your backend we will save this and even if the user changes their device ID we will keep their progress.**&#x20;
  {% endhint %}

***

### 3. Showing the Offerwall

Once initialized and logged in, you can display the Offerwall.

> \[!NOTE] **Context Free**: You no longer need to pass a `BuildContext` to `showOffers()`. The SDK uses the global `navigatorKey` provided during initialization.

```dart
// Opens the default offers page
await Tyrads.instance.showOffers();

// Opens the offerwall with specific routing
await Tyrads.instance.showOffers(
  route: TyradsDeepRoutes.ACTIVE_OFFERS,
  // campaignID: 12345, // Required for specific campaign routes
);
```

<details>

<summary><strong>Launch Mode</strong></summary>

The Tyrads SDK provides two primary ways to display the Offerwall to your users. You can configure this globally during initialization or override it for specific calls.

#### TyradsLaunchMode Types

| Mode              | Description                                                                               |
| ----------------- | ----------------------------------------------------------------------------------------- |
| `webview`         | **(Default)** Opens the Offerwall within an internal SDK-managed WebView inside your app. |
| `externalBrowser` | Opens the Offerwall in the user's default system browser (e.g., Chrome, Safari).          |

***

#### 1. Global Configuration

Set the default launch behavior during SDK initialization:

```dart
await Tyrads.instance.init(
  navigatorKey: hostNavigatorKey,
  apiKey: "YOUR_API_KEY",
  apiSecret: "YOUR_API_SECRET",
  launchMode: TyradsLaunchMode.webview, // Global default
);
```

#### 2. Manual Override

Override the global setting when calling `showOffers`:

```dart
// Force this specific opening to use the external browser
await Tyrads.instance.showOffers(
  launchMode: TyradsLaunchMode.externalBrowser,
);
```

#### 3. Dynamic Update

You can also change the global launch mode at any time after initialization:

```dart
Tyrads.instance.setLaunchMode(TyradsLaunchMode.externalBrowser);
```

***

> \[!IMPORTANT] **Safety & Integrity**: Even when using `externalBrowser` mode, the SDK automatically performs all mandatory checks (Login, SDK Initialization, and Onboarding) before triggering the redirection. This ensures user tracking and campaign attribution remain 100% accurate.

</details>

#### Deep Link Routes

**Min SDK version required: v1.1.4**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

| Route Name                                                    | Constant                         | Description                                            |
| ------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------ |
| `offers`                                                      | `TyradsDeepRoutes.OFFERS`        | Main campaigns list (Default)                          |
| `active-offers`                                               | `TyradsDeepRoutes.ACTIVE_OFFERS` | User's activated campaigns                             |
| `offers/`<mark style="color:$warning;">`[campaign-id]`</mark> | `TyradsDeepRoutes.OFFERS`        | Specific campaign details (Requires `campaignID`)      |
| `support`                                                     | `TyradsDeepRoutes.SUPPORT`       | Support tickets for a campaign (Requires `campaignID`) |

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active-offers` - opens the Activated Campaigns Page
* `offers/`<mark style="color:$warning;">`[campaign-id]`</mark> - opens the Campaign Details Page (requires campaignID)
* `support` - opens the Campaign Tickets Page (requires campaignID)

```dart
// Note: CAMPAIGNS is the default route when no specific route is provided
await Tyrads.instance.showOffers();

// Explicitly specifying the Campaigns Page
await Tyrads.instance.showOffers(route: "offers");
//or use TyradsDeepRoutes class to avoid typos
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.OFFERS);

// Activated Campaigns Page
await Tyrads.instance.showOffers(route: "active-offers");
// or using TyradsDeepRoutes class like
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.ACTIVE_OFFERS);

// Campaign Details Page (requires campaignID)
await Tyrads.instance.showOffers(route: "offer", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.OFFER, campaignID: "your_campaign_id_here");

// Campaign Tickets Page (requires campaignID)
await Tyrads.instance.showOffers(route: "support", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.SUPPORT, campaignID: "your_campaign_id_here");
```

***

### 4. Premium Offers Widget

The **PremiumOffersWidget** is a standalone UI element that displays a preview of top offers. It is highly flexible and can be embedded anywhere in your UI.

#### Integration

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

class MyHomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const Text("Recommended for you:"),
        // Standalone widget — works without context parameters
        const PremiumOffersWidget(
          widgetStyle: PremiumWidgetStyles.sliderCards,
        ),
      ],
    );
  }
}
```

#### Widget Styles

* **`PremiumWidgetStyles.list`**: A standard vertical list layout (Default).
* **`PremiumWidgetStyles.sliderCards`**: A horizontal, swipeable card carousel.

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

***

### 5. Localization

You can change the SDK language dynamically at runtime. This choice is persisted across app sessions.

```dart
// Supported codes: en, es, id, ja, ko, zh-Hans-CN
await Tyrads.instance.changeLanguage("es"); // Change to Spanish
```

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.

***

### 6. Callbacks

Register callbacks to monitor user actions within the SDK:

```dart
Tyrads.instance.setCallback(TyradsCallbackType.activated, (data) {
  print("User activated a campaign: $data");
});

Tyrads.instance.setCallback(TyradsCallbackType.campaignDetail, (data) {
  print("User viewed campaign details: $data");
});
```


# Deeplinking Routes

**Min SDK version required: v1.1.4**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

| Route Name                                                     | Constant                         | Description                                            |
| -------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------ |
| `offers`                                                       | `TyradsDeepRoutes.OFFERS`        | Main campaigns list (Default)                          |
| `active-offers`                                                | `TyradsDeepRoutes.ACTIVE_OFFERS` | User's activated campaigns                             |
| `offers/`<mark style="color:$warning;">`[campaign-id]`</mark>  | `TyradsDeepRoutes.OFFERS`        | Specific campaign details (Requires `campaignID`)      |
| `support/`<mark style="color:$warning;">`[campaign-id]`</mark> | `TyradsDeepRoutes.SUPPORT`       | Support tickets for a campaign (Requires `campaignID`) |

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active-offers` - opens the Activated Campaigns Page
* `offers/`<mark style="color:$warning;">`[campaign-id]`</mark> - opens the Campaign Details Page (requires campaignID)
* `support/`<mark style="color:$warning;">`[campaign-id]`</mark> - opens the Campaign Tickets Page (requires campaignID)

```dart
// Note: CAMPAIGNS is the default route when no specific route is provided
await Tyrads.instance.showOffers();

// Explicitly specifying the Campaigns Page
await Tyrads.instance.showOffers(route: "offers");
//or use TyradsDeepRoutes class to avoid typos
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.OFFERS);

// Activated Campaigns Page
await Tyrads.instance.showOffers(route: "active-offers");
// or using TyradsDeepRoutes class like
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.ACTIVE_OFFERS);

// Campaign Details Page (requires campaignID)
await Tyrads.instance.showOffers(route: "offer", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.OFFER, campaignID: "your_campaign_id_here");

// Campaign Tickets Page (requires campaignID)
await Tyrads.instance.showOffers(route: "support", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
await Tyrads.instance.showOffers(route: TyradsDeepRoutes.SUPPORT, campaignID: "your_campaign_id_here");
```


# Premium Offers

The **PremiumOffersWidget** is a standalone, high performance UI component that becomes available immediately after SDK initialisation. It is designed to be highly flexible, allowing you to embed it anywhere in your application's widget tree.

**Key Features:**

* **More Offers**: Seamlessly opens the full Offerwall.
* **Active Offers**: Quick access to a user's currently active campaigns.
* **Campaign Details**: Direct navigation to specific campaign records.
* **Play**: Intelligent routing to activate the offer and redirect to appropriate app store.

***

**1. Usage**

Unlike the previous version, the widget is now a standalone class. You no longer need to call a method on the Tyrads instance or provide a `BuildContext`.

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

class MyOffersPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Top Rewards')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            // Standard integration, no parameters required
            const PremiumOffersWidget(), 
            
            // ... your other widgets
          ],
        ),
      ),
    );
  }
}
```

***

**2. Customization Options**

You can control the visual presentation of the offers using the `widgetStyle` parameter.

<table><thead><tr><th width="153">Parameter</th><th width="207">Type</th><th width="108">Default</th><th>Description</th></tr></thead><tbody><tr><td><code>widgetStyle</code></td><td><code>PremiumWidgetStyles</code></td><td><code>.list</code></td><td>Determines the layout of the offers.</td></tr></tbody></table>

**Available Styles:**

* `PremiumWidgetStyles.list`: Displays offers in a vertical list.
* `PremiumWidgetStyles.sliderCards`: Displays offers in a horizontal, swipeable card carousel.

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

**Example with Custom Style:**

```dart
const PremiumOffersWidget(
  widgetStyle: PremiumWidgetStyles.sliderCards,
)
```

***

**3. Technical Requirements**

* **SDK Initialization**: Ensure `Tyrads.instance.init()` and `loginUser()` have been called before the widget is rendered.
* **Global Navigation**: The widget automatically leverages the `navigatorKey` provided during SDK initialization. No manual context passing is required.


# Localization

This asynchronous method allows you to change the language used by the Tyrads SDK. It updates the SDK's internal locale settings.

```dart
await Tyrads.instance.changeLanguage("en");
```

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.

#### Usage Example:

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

ElevatedButton(
  onPressed: () async {
    await Tyrads.instance.changeLanguage('es'); // Change to Spanish
  },
  child: Text('Change to Spanish'),
),
```

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.


# Obtaining Advertising ID's

**Android 12**

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the AndroidManifest.xml file.

Navigate to the `android/app/src/main` directory inside your project's root, locate the AndroidManifest.xml file and add the following line just before the `<application>`.

Copy

<pre><code><strong>&#x3C;uses-permission android:name="com.google.android.gms.permission.AD_ID" />
</strong></code></pre>

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248).

**iOS 14+**

You need to add `NSUserTrackingUsageDescription` to `Info.plist` file like

```
<key>NSUserTrackingUsageDescription</key>
<string>We use device identification to personalize your rewards experience, track your progress, and provide tailored offers. This helps us improve our services and ensure you get the most value from our rewards program.</string>
```

Request IDFA Permission&#x20;

Tyrads SDK can work with or without the IDFA permission on iOS 14+. If no permission is granted in the ATT popup, the SDK will serve non personalized offers to the user. In that scenario the conversion is expected to be lower. Offerwall integrations perform better compared to when no IDFA permission is given. Our recommendation is that you should ask for IDFA usage permission prior to Tyrads sdk initialization.

```
<key>NSUserTrackingUsageDescription</key>
	<string>We use device identification to personalize your rewards experience, track your progress, and provide tailored offers. This helps us improve our services and ensure you get the most value from our rewards program.</string>

```


# Prerequisites

Before you begin, ensure you have met the following requirements:

* You have obtained your API key and API secret from the TyrAds.
* You have Node.js installed (version 18.0 or later recommended).
* For React Native projects, ensure you have React Native CLI installed and your development environment set up.


# Installation

To install the `@tyrads.com/tyrads-sdk` package, run the following command: `npm install @tyrads.com/tyrads-sdk`


# Initialization

This guide provides detailed instructions on how to properly initialize and integrate the Tyrads SDK into your React Native application.

### Table of Contents

1. [Overview](#overview)
2. [Initialization Timing](#initialization-timing)
3. [The `Tyrads.init` Method](#the-tyrads.init-method)
4. [Data Structures](#data-structures)
5. [User Authentication](#user-authentication)
6. [Displaying Offers](#displaying-offers)
7. [iOS Launch Modes](#ios-launch-modes)
8. [Deeplinking & Routing](#deeplinking-and-routing)

***

### Overview

Tyrads SDK introduces a more modular approach to offerwall integration, including native React components and enhanced data tracking capabilities. To ensure optimal user experience and accurate attribution, please follow the initialization patterns described below.

### Initialization Timing

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

#### MMP & Media Source Dependency

**CRITICAL**: It is highly recommended to initialize the Tyrads SDK **only after** your Mobile Measurement Partner (MMP) or internal media source data has been fully resolved.

Initializing the SDK with valid media source data ensures:

* **Accurate Attribution**: Users are correctly mapped to their acquisition sources.
* **Customized Rewards**: The earning journey can be tailored based on the user's entry point.
* **Better Analytics**: Provides clearer feedback on the quality of users from different segments.

***

### The `Tyrads.init` Method

The `init` method is the entry point for the SDK. In v4, several optional parameters have been added to provide more context about the user and the session.

```typescript
await Tyrads.init(
  apiKey: string,
  apiSecret: string,
  encKey?: string,
  engagementId?: string,
  placementId?: string,
  mediaSourceInfo?: TyradsMediaSourceInfo,
  userInfo?: TyradsUserInfo,
  config?: TyradsConfig
);
```

#### Parameter Details

| Parameter         | Type                    | Required | Description                                                                                                                                             |
| ----------------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`          | `string`                | **Yes**  | Your unique Tyrads API Key.                                                                                                                             |
| `apiSecret`       | `string`                | **Yes**  | Your unique Tyrads API Secret.                                                                                                                          |
| `encKey`          | `string`                | No       | **Encryption Key**. Used for encrypting data transmitted from the SDK. If omitted, data is sent in plain text.                                          |
| `engagementId`    | `string`                | No       | A unique identifier for tracking specific user engagement campaigns.                                                                                    |
| `placementId`     | `string`                | No       | Used to differentiate between different  coins and use as per your selection within your app.                                                           |
| `mediaSourceInfo` | `TyradsMediaSourceInfo` | No       | Detailed attribution data (see [Data Structures](#data-structures)).                                                                                    |
| `userInfo`        | `TyradsUserInfo`        | No       | Additional user metadata like email or user group.                                                                                                      |
| `config`          | `TyradsConfig`          | No       | <p><strong>Android Only</strong>: </p><p>SDK behavioral configuration such as <code>skipInitialPages</code> to bypass privacy/permission screens. .</p> |

***

### Data Structures

#### TyradsMediaSourceInfo

Used to provide the SDK with information about the user's acquisition source.

```typescript
export interface TyradsMediaSourceInfo {
  mediaSourceName?: string;    // (e.g. "Facebook", "Google")
  mediaCampaignName?: string;  // e.g., "Summer_Sale_2024"
  mediaSourceId?: string;      // Unique ID from the source
  mediaSubSourceId?: string;   // Sub-identifier for the source
  incentivized?: boolean;      // Whether the traffic is incentivized
  mediaAdsetName?: string;
  mediaAdsetId?: string;
  mediaCreativeName?: string;
  mediaCreativeId?: string;
  sub1?: string;               // Custom tracking parameters (sub1 - sub5)
  sub2?: string;
  sub3?: string;
  sub4?: string;
  sub5?: string;
}
```

#### TyradsUserInfo

Provides basic demographic or segment data for the user.

```typescript
export interface TyradsUserInfo {
  email?: string;
  phoneNumber?: string;
  userGroup?: string;          // e.g., "premium", "freetier"
  age?: number;                // User age
  gender?: number;             // 1 for Male, 2 for Female
}
```

***

### User Authentication

After initialization, you must identify the user before showing offers.

```javascript
// This ID should be unique to the user in your system
await Tyrads.loginUser('unique_user_id_123');
```

***

### Displaying Offers

You can display the full offerwall or use native components.

#### Full Offerwall (Modal/Browser)

```javascript
await Tyrads.showOffers();
```

#### Native Premium Widget

Render premium offers directly inside your React components for a more native feel.

```jsx
import { PremiumOffersWidget, PremiumOffersWidgetLoading, PremiumWidgetStyles  } from '@tyrads.com/tyrads-sdk';

const MyComponent = () => (
  <View>
    <PremiumOffersWidget widgetStyle={PremiumWidgetStyles.list} />
  </View>
);
```

The `PremiumWidgetStyles` enum allows you to choose between two distinct layouts:

| Style                             | Description                                                                                |
| --------------------------------- | ------------------------------------------------------------------------------------------ |
| `PremiumWidgetStyles.list`        | Renders offers in a vertical list format (Best for dedicated offer screens).               |
| `PremiumWidgetStyles.sliderCards` | Renders offers in a horizontal swipeable carousel (Best for home screens or small spaces). |

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>sliderCards</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>list</p></figcaption></figure>

***

### iOS Launch Modes

On iOS, you can control how the offerwall is presented to comply with Apple's policies.

| Mode         | Value | Behavior                                      |
| ------------ | ----- | --------------------------------------------- |
| **External** | `3`   | Opens the Offerwall in Safari (Default).      |
| **Embedded** | `2`   | Opens the Offerwall in an embedded WKWebView. |

```javascript
// Open in embedded view
await Tyrads.showOffers({ launchMode: 2 });
```

***

### Deeplinking & Routing

The SDK supports routing users directly to specific sections of the offerwall.

| Route           | Description                             | Requires `campaignID`? |
| --------------- | --------------------------------------- | ---------------------- |
| `offers`        | Main campaigns list                     | No                     |
| `active-offers` | List of user's active campaigns         | No                     |
| `offers`        | Details for a specific campaign         | **Yes**                |
| `support`       | Support tickets for a specific campaign | **Yes**                |

**Example Usage:**

```javascript
// Open details for a specific campaign
await Tyrads.showOffers({ 
  route: "offers", 
  campaignID: "your_campaign_id" 
});
```


# Deeplinking & Routes

**Min SDK version required: v1.1.4**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active-offers` - opens the Activated Campaigns Page
* `offers/`<mark style="color:$warning;">`[id]`</mark> - opens the Campaign Details Page (requires campaignID)
* `support/`<mark style="color:$warning;">`[id]`</mark> - opens the Campaign Tickets Page (requires campaignID

| Route                                                 | Description                             | Requires `campaignID`? |
| ----------------------------------------------------- | --------------------------------------- | ---------------------- |
| `offers`                                              | Main campaigns list                     | No                     |
| `active-offers`                                       | List of user's active campaigns         | No                     |
| `offers/`<mark style="color:$warning;">`[id]`</mark>  | Details for a specific campaign         | **Yes**                |
| `support/`<mark style="color:$warning;">`[id]`</mark> | Support tickets for a specific campaign | **Yes**                |

**Example Usage:**

```javascript
// Open details for a specific campaign
await Tyrads.showOffers({ 
  route: "offers", 
  campaignID: "your_campaign_id" 
});
```


# Premium Offers

Tyrads SDK  introduces native React components that allow you to render premium offers directly within your application's UI, providing a more integrated and seamless user experience compared to the traditional modal offerwall.

***

### Components Overview

The SDK exports two primary components for native widget implementation:

* **`PremiumOffersWidget`**: The main component that fetches and displays premium offers.
* **`PremiumOffersWidgetLoading`**: A placeholder component that provides a skeleton/shimmer effect during data fetching.

***

### Basic Usage

To use the premium widget, simply import it and place it anywhere in your JSX tree.

```jsx
import React from 'react';
import { View, ScrollView } from 'react-native';
import { PremiumOffersWidget, PremiumWidgetStyles } from '@tyrads.com/tyrads-sdk';

const MyGameScreen = () => {
  return (
    <ScrollView>
      {/* Other game content */}
      
      <PremiumOffersWidget 
        widgetStyle={PremiumWidgetStyles.list} 
        launchMode={2}
      />
      
      {/* Other game content */}
    </ScrollView>
  );
};
```

***

### Widget Styles

The `PremiumWidgetStyles` enum allows you to choose between two distinct layouts:

| Style                             | Description                                                                                |
| --------------------------------- | ------------------------------------------------------------------------------------------ |
| `PremiumWidgetStyles.list`        | Renders offers in a vertical list format (Best for dedicated offer screens).               |
| `PremiumWidgetStyles.sliderCards` | Renders offers in a horizontal swipeable carousel (Best for home screens or small spaces). |

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

**Example (Slider Style):**

```jsx
<PremiumOffersWidget widgetStyle={PremiumWidgetStyles.sliderCards} />
```

***

### Prop Reference

#### `PremiumOffersWidget`

| Prop          | Type                  | Default | Description                                                             |
| ------------- | --------------------- | ------- | ----------------------------------------------------------------------- |
| `widgetStyle` | `PremiumWidgetStyles` | `list`  | Determines the layout of the widget.                                    |
| `launchMode`  | `number`              | `2`     | Determines presentation style on iOS (2: Embedded, 3: External Safari). |

#### `PremiumOffersWidgetLoading`

| Prop          | Type                  | Default | Description                                                |
| ------------- | --------------------- | ------- | ---------------------------------------------------------- |
| `widgetStyle` | `PremiumWidgetStyles` | `list`  | Matches the skeleton layout to your intended widget style. |

***

### Handling Loading States

For the best user experience, it's recommended to show the loading placeholder while the SDK is initializing or fetching data.

```jsx
import React, { useState, useEffect } from 'react';
import Tyrads, { PremiumOffersWidget, PremiumOffersWidgetLoading } from '@tyrads.com/tyrads-sdk';

const MyScreen = () => {
  const [isReady, setReady] = useState(false);

  useEffect(() => {
    Tyrads.init('KEY', 'SECRET').then(() => {
      Tyrads.loginUser('USER_ID').then(() => {
        setReady(true);
      });
    });
  }, []);

  return (
    <View style={{ flex: 1 }}>
      {isReady ? (
        <PremiumOffersWidget />
      ) : (
        <PremiumOffersWidgetLoading />
      )}
    </View>
  );
};
```

***

### Best Practices

1. **Container Sizing**: The `PremiumOffersWidget` is designed to be flexible. If using the `list` style inside a `ScrollView`, ensure it doesn't have a fixed height unless intended.
2. **Launch Mode Compatibility**: Remember that `launchMode` only affects iOS presenting behavior. On Android, the offer details always open in the standard view.
3. **Key Management**: If your app supports multiple configurations or user switching, you can use the `key` prop on the widget to force a re-render when initialization data changes.


# Localization

This asynchronous method allows you to change the language used by the Tyrads SDK. It updates the SDK's internal locale settings.

<pre class="language-dart"><code class="lang-dart"><strong>await Tyrads.changeLanguage("en");
</strong></code></pre>

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.

#### Usage Example:

```javascript
<TouchableOpacity
  onPress={async () => {
    await Tyrads.changeLanguage("id");
  }}
>
  <Text>
    Change Language
  </Text>
</TouchableOpacity>
```

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.


# Obtaining Advertising ID's

**Android 12**

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the AndroidManifest.xml file.

Navigate to the `android/app/src/main` directory inside your project's root, locate the AndroidManifest.xml file and add the following line just before the `<application>`.

Copy

```
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
```

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248).

**iOS 14+**

You need to add `NSUserTrackingUsageDescription` to `Info.plist` file like

```
<key>NSUserTrackingUsageDescription</key>
<string>We use device identification to personalize your rewards experience, track your progress, and provide tailored offers. This helps us improve our services and ensure you get the most value from our rewards program.</string>
```

Request IDFA Permission

Tyrads SDK can work with or without the IDFA permission on iOS 14+. If no permission is granted in the ATT popup, the SDK will serve non personalized offers to the user. In that scenario the conversion is expected to be lower. Offerwall integrations perform better compared to when no IDFA permission is given. Our recommendation is that you should ask for IDFA usage permission prior to Tyrads sdk initialization.

```
<key>NSUserTrackingUsageDescription</key>
	<string>We use device identification to personalize your rewards experience, track your progress, and provide tailored offers. This helps us improve our services and ensure you get the most value from our rewards program.</string>
```


# Native Dependency Troubleshooting

If the Tyrads SDK is installed but you encounter errors like `Native component for "BVLinearGradient" not found` , it means the React Native **Auto-linking** process failed to pick up the native dependencies.

This is common in monorepos, local workspace links, or complex project structures. Follow these steps to manually link the required dependencies.

***

### 1. Required Dependencies

The Tyrads SDK relies on the following dependencies which should be installed in your host app:

* `react-native-linear-gradient` (Native)
* `react-native-snap-carousel` (JS)

***

### 2. Android Manual Linking

If you see `BVLinearGradient not found` on Android, perform these steps:

#### A. Update `android/settings.gradle`

Add the following lines to include the native projects:

```gradle
include ':react-native-linear-gradient'
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
```

#### B. Update `android/app/build.gradle`

Add the implementation lines to your `dependencies` block:

```gradle
dependencies {
    // ... other dependencies
    implementation project(':react-native-linear-gradient')
}
```

#### C. Update `MainApplication.kt`

Manually register the packages in your `getPackages()` method:

```kotlin
import com.BV.LinearGradient.LinearGradientPackage

// ...

override fun getPackages(): List<ReactPackage> =
    PackageList(this).packages.apply {
        // Packages that cannot be autolinked yet can be added manually here
        add(LinearGradientPackage())
    }
```

***

### 3. iOS Manual Linking

If you encounter issues on iOS, follow these steps:

#### A. Update `ios/Podfile`

Ensure the pods are explicitly listed if they aren't being picked up:

```ruby
target 'YourAppName' do
  # ... other pods
  pod 'react-native-linear-gradient', :path => '../node_modules/react-native-linear-gradient'
end
```

#### B. Run Pod Install

After updating the Podfile, navigate to the `ios` directory and run:

```bash
pod install
```

***

### 4. Rebuild the App

After making any native changes, you **must** perform a clean build:

```bash
# Android
yarn android

# iOS
yarn ios
```


# Initialization

Integrating TyrAds web is easy and can be done by just passing the url in the in-app-browser or iframe:

```
https://websdk.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&encKey=YOUR_ENCRYPTION_KEY&userID=CUSTOMER_USER_ID&platform=web&av=3&sdkVersion=3.0.0
```

Just replace the following values with your own.

* YOUR\_API\_KEY
* YOUR\_API\_SECRET
* YOUR\_ENCRYPTION\_KEY

encKey: This is the newly added parameter. It stands for "encryption key" and would be used for encrypting data transmitted from the iframe. If not provided data will be transmitted plain form.

* CUSTOMER\_USER\_ID

\
The sdkVersion parameter now operates under the following logic:\
If sdkVersion is NOT provided in the URL: The system will default to displaying v2.0.\
If sdkVersion IS provided and is 3.0.0 or greater: The system will display v3.0

**Deeplinking Routes**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `campaigns` - opens the Campaigns Page
* `campaigns-activated` - opens the Activated Campaigns Page
* `campaign-details` - opens the Campaign Details Page (requires campaignID)
* `campaign-tickets` - opens the Campaign Tickets Page (requires campaignID)

```

// Note: CAMPAIGNS is the default route when no specific route is provided

https://websdk.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=CUSTOMER_USER_ID&platform=web

// Explicitly specifying the Campaigns Page by appending `&route=campaigns` to the URL

https://websdk.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=CUSTOMER_USER_ID&platform=web&route=campaigns

// Activated Campaigns Page by appending `&route=campaigns-activated` to the URL

https://websdk.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=CUSTOMER_USER_ID&platform=web&route=campaigns-activated

// Campaign Details Page (requires campaignID) by appending `&route=campaign-details&campaignID=YOUR_CAMPAIGN_ID` to the URL

https://websdk.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=CUSTOMER_USER_ID&platform=web&route=campaign-details&campaignID=YOUR_CAMPAIGN_ID

// Campaign Tickets Page (requires campaignID) by appending `&route=campaign-tickets&campaignID=YOUR_CAMPAIGN_ID` to the URL

https://websdk.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=CUSTOMER_USER_ID&platform=web&route=campaign-tickets&campaignID=YOUR_CAMPAIGN_ID


```

If your website is using html, you can use the following steps to integrate TyrAds web:

* add an iframe to your page

```html
<iframe id="tyrads_iframe" src="" height="650" width="300"></iframe>
```

* provide the source URL dynamically to the iframe src attribute

```js
<script type="text/javascript" deffered>
        (function () {

                var frameElement = document.getElementById("tyrads_iframe");
                var apiKey = "YOUR API KEY"
                var apiSecret = "YOUR API SECRET"
                var userId = "1234567890"
                frameElement.src = "https://websdk.tyrads.com/?apiKey=" + apiKey + "&apiSecret=" + apiSecret + "&userID=" + userId + "&platform=web";

        })();  
</script>
```

### Localization

#### Introduction

Localization is a crucial feature that allows our application to support multiple languages, enhancing user experience across different regions. This documentation explains how to use the localization feature in our application, both through URL parameters and internal web application settings.

#### Localization via URL Parameters

**Overview**

To specify the language for our application using URL parameters, you can append the `lang` parameter to the URL. This method is useful for direct linking to language-specific pages.

**Supported Languages**

The following languages are supported:

* **English (en)**
* **Spanish (es)**
* **Indonesian (id)**
* **Korean (ko)**
* **Japanese (ja)**

**Usage Example**

To access the application in Korean, you would use the following URL:

```http
http://example.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=YOUR_USER_ID&newUser=false&platform=Android&hc=%23000F1E&mc=%232CB388&route=null&campaignID=null&sdk_version=1.1.11&av=3.0&lang=ko
```

#### Localization Inside the Web Application

**Overview**

In addition to using URL parameters, the web application itself can change the localization settings. This allows users to switch languages directly within the application.

**Supported Languages**

The same set of languages is supported as with the URL parameter method:

* **English (en)**
* **Spanish (es)**
* **Indonesian (id)**
* **Korean (ko)**
* **Japanese (ja)**

**Usage**

1. **Access the Localization Settings**: Navigate to the settings or preferences section of the web application.
2. **Select Language**: Choose your preferred language from the list of supported languages.
3. **Apply Changes**: Save your selection to update the application's language.

#### Best Practices

* **URL Encoding**: When using URL parameters, ensure that special characters are properly encoded to avoid errors.
* **Language Codes**: Use standard ISO language codes (e.g., `en` for English) for consistency and compatibility.
* **Testing**: Always test the application in each supported language to ensure proper rendering and functionality.

#### Troubleshooting

* **Unsupported Languages**: If a language is not supported, the application may default to a fallback language English (`en`).
*


# Iframe Publisher Support Tickets

Here is the detailed documentation for&#x20;

***

## How to Use Iframe Publisher Support Tickets

### Overview

The **Iframe Publisher Support Tickets** system allows publishers to manage and track support tickets seamlessly within their platform using iframe integration. This guide explains how to set up and use the iframe for accessing TyrAds' publisher support ticket system.

***

### Prerequisites

Before integrating the iframe for support tickets, ensure you have:

1. **API Key**: A unique identifier for your account.
2. **API Secret**: A secure token for authentication.
3. **User ID**: Your unique publisher ID.
4. **Platform Information**: Specify whether you’re using "web" or "mobile".
5. **Campaign ID**: Optional, if related to a specific campaign.

***

#### Steps: Embed the Iframe Widget

To integrate the iframe widget into your platform, follow these steps:

**1. Copy the Iframe URL**

Use the following iframe url:

```html
https://publisher-support.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=YOUR_USER_ID&platform=PLATFORM_TYPE&campaignID=CAMPAIGN_ID

```

**2. Replace Placeholder Values**

Replace the placeholders in the iframe code with your actual credentials:

* `YOUR_API_KEY`: Replace with your API Key.
* `YOUR_API_SECRET`: Replace with your API Secret.
* `YOUR_USER_ID`: Replace with your User ID.
* `PLATFORM_TYPE`: Specify "web".
* `CAMPAIGN_ID`: Replace with the Campaign ID (optional).

### Features of Publisher Support Tickets

* **Ticket Submission**: Publishers can submit queries or issues directly through the iframe.
* **Ticket Tracking**: View and track the status of submitted tickets in real time.
* **Campaign-Specific Queries**: If a campaign ID is provided, tickets can be linked to specific campaigns.

***

### Troubleshooting

#### Common Issues:

1. **Iframe Not Loading**:
   * Verify that all credentials (API Key, Secret, User ID) are correct.
   * Ensure there is no typo in the iframe URL.
   * Ensure your campaignID is correct.
2. **Authentication Errors**:
   * Confirm that your API Key and Secret are valid and active.

***

### Conclusion

Iframe Publisher Support Tickets provide a streamlined way for publishers to manage their interactions with TyrAds support directly within their platform. By following this guide, you can ensure proper setup and efficient use of this feature.


# Premium Widgets

**Premium Widgets** with parameters `pc` (Premium Color) and `widgetStyle` (1, 2, 3, 4)

***

## How to Use Premium Widgets

### Overview

Premium widgets provide a customizable way to display engaging content or offers on your platform. The `pc` (Premium Color) parameter allows you to define the widget's primary color, while the `widgetStyle` parameter offers four predefined styles to match your platform's design.

This guide explains how to integrate and customize these premium widgets using the provided URL structure.

***

### Prerequisites

Before integrating premium widgets, ensure you have:

1. **API Key**: A unique identifier for your account.
2. **API Secret**: A secure token for authentication.
3. **User ID**: Your unique publisher ID.
4. **Platform Information**: Specify "web" or "mobile".
5. **Custom Parameters**:
   * `pc`: Hexadecimal color code for widget customization.
   * `widgetStyle`: Choose from styles 1, 2, 3, or 4.

***

### Integration Steps

#### Steps: Embed the Iframe Widget

To integrate the premium widget into your platform, follow these steps:

**1. Copy the Iframe Code**

Use the following iframe template:

```html
https://sdk-widget.tyrads.com/?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userID=YOUR_USER_ID&platform=PLATFORM_TYPE&pc=COLOR_CODE&widgetStyle=STYLE_NUMBER

```

**2. Replace Placeholder Values**

Replace the placeholders in the iframe code with your actual credentials:

* `YOUR_API_KEY`: Replace with your API Key.
* `YOUR_API_SECRET`: Replace with your API Secret.
* `YOUR_USER_ID`: Replace with your User ID.
* `PLATFORM_TYPE`: Specify "web" or "mobile".
* `COLOR_CODE`: Replace with a hex color code (e.g., `#7e7e7e`).
* `STYLE_NUMBER`: Choose one of the predefined styles (1, 2, 3, or 4).

### Parameters Explained

#### 1. **pc (Premium Color)**

* Defines the primary color of the widget.
* Use hexadecimal color codes (e.g., `#FF5733` for orange).
* Example: To set a gray theme, use `pc=%237e7e7e` in url bar.

#### 2. **widgetStyle**

* Determines the widget's layout and appearance.
* Available styles:
  * **1**: Minimalist design.
  * **2**: Modern layout with rounded edges.
  * **3**: Compact style for smaller spaces.
  * **4**: Bold and vibrant design for maximum engagement.
* Example: To use style 2, set `widgetStyle=2`.

***

### Features of Premium Widgets

* **Customizable Appearance**: Adjust colors and styles to match your branding.
* **Responsive Design**: Widgets adapt to different screen sizes automatically.
* **Interactive Content**: Engages users with visually appealing offers.

***

### Troubleshooting

#### Common Issues:

1. **Widget Not Loading**:
   * Verify that all credentials (API Key, Secret, User ID) are correct.
   * Ensure there is no typo in the iframe URL.
2. **Incorrect Colors or Styles**:
   * Double-check the hex color code and style number in the URL.
3. **Authentication Errors**:
   * Confirm that your API Key and Secret are valid and active.

***

### Conclusion

Premium Widgets offer a flexible and visually appealing way to enhance user engagement on your platform. By customizing colors (`pc`) and styles (`widgetStyle`), you can seamlessly integrate these widgets into your application while maintaining brand consistency.


# Installation

Step-by-step instructions for installing and configuring TyrAds SDK Iframe in your applications. These integration guides help you quickly add TyrAds SDK Iframe to your applications.

{% content-ref url="/pages/bsMFqepu4g1807em24dj" %}
[NodeJS](/iframe/installation/nodejs)
{% endcontent-ref %}

{% content-ref url="/pages/YP15Qv4fWQcMX4oZUPEB" %}
[Manual Integration](/iframe/installation/manual-integration)
{% endcontent-ref %}


# PHP

Integrate your PHP app with us using our PHP package

> This library supports PHP 5.5+

## Installation

Add `tyrads/tyrads-sdk` to your `composer.json` as follows:

```sh
composer require tyrads/tyrads-sdk
```

> The latest available version of PHP  `tyrads/tyrads-sdk`  is [v0.4.1](https://github.com/tyrads-com/tyrads-php-sdk-iframe/releases/tag/v0.4.1).

## Get Started

After successfully installing our package, create a TyrAdsSdk object with your API key and API secret:

```php
use Tyrads\TyradsSdk\TyrAdsSdk;

$tyrAdsSdk = TyrAdsSdk::make("API_KEY", "API_SECRET");
```

### Localization

This `TyrAdsSdk` class also supports localization, more info about [localization](/iframe/installation/manual-integration#localization)

For example:

```php
$tyrAdsSdk = TyrAdsSdk::make("API_KEY", "API_SECRET", "en");
```

## Authentication

You can do the authentication by calling to our package

```php
$authRequest = new AuthenticationRequest(
    "PUBLISHER_USER_ID", // Publisher User
);
$authSign = $tyrAdsSdk->authenticate(
    $authRequest
);
```

After obtaining the token successfully, you can call `iframeUrl` method to get the iframe URL

```php
$url = $tyrAdsSdk->iframeUrl($authSign->getToken());
// Result: https://sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

{% hint style="info" %}

1. A new token must be requested each time a user wants to access the offerwall.
2. Each token is valid for **7 days** only
   {% endhint %}

### Deeplinking Routes

This `iframeUrl` method also supports deeplinking, more info about [deeplinking routes](/iframe/installation/manual-integration#deeplinking-routes)

For example:

```php
$url = $tyrAdsSdk->iframeUrl($authSign->getToken(), "/settings/language");
// Result: https://sdk.tyrads.com?to=/settings/language&token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

### Embedding The Iframe

If your website is using html, you can add an iframe to your page to integrate TyrAds web:

```html
<iframe id="tyrads_iframe" src="[IFRAME_LINK]" height="650" width="300"></iframe>
```

For example:

```html
<iframe id="tyrads_iframe" src="https://sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==" height="650" width="300"></iframe>
```

## Example

For example implementation using our PHP SDK, you can find it here

{% embed url="<https://github.com/tyrads-com/php-sdk-iframe-example/blob/main/TyrAdsSdk/src/index.php>" %}


# NodeJS

Integrate your NodeJS app with us using our NodeJS package

## Installation

Add `@tyrads.com/tyrads-sdk-iframe` to your `package.json` as follows:

```
npm install --save @tyrads.com/tyrads-sdk-iframe
# or
yarn add @tyrads.com/tyrads-sdk-iframe
```

> The latest available version of NodeJS  `@tyrads.com/tyrads-sdk-iframe`  is [v0.2.2](https://github.com/tyrads-com/tyrads-node-sdk-iframe/releases/tag/v0.2.2).

## Get Started

After successfully installing our package, create a TyrAdsSdk object with your API key and API secret:

```php
const tyradsSDK = TyradsSDK.make(API_KEY, API_SECRET);
```

### Localization

This `TyrAdsSdk` class also supports localization, more info about [localization](/iframe/installation/manual-integration#localization)

For example:

```php
const tyradsSDK = TyradsSDK.make(API_KEY, API_SECRET, "en");
```

## Authentication

You can do the authentication by calling to our package

```php
const authResponse = await tyradsSDK.authenticate({
    "PUBLISHER_USER_ID", // Publisher User ID
});
```

After obtaining the token successfully, you can call `iframeUrl` method to get the iframe URL

```php
const iframeUrl = tyradsSDK.iframeUrl(authResponse.getToken())
// Result: https://sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

{% hint style="info" %}

1. A new token must be requested each time a user wants to access the offerwall.
2. Each token is valid for **7 days** only
   {% endhint %}

### Deeplinking Routes

This `iframeUrl` method also supports deeplinking, more info about [deeplinking routes](/iframe/installation/manual-integration#deeplinking-routes)

For example:

```php
const iframeUrl = tyradsSDK.iframeUrl(authResponse.getToken(), "/settings/language")
// Result: https://sdk.tyrads.com?to=/settings/language&token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

### Embedding The Iframe

If your website is using html, you can add an iframe to your page to integrate TyrAds web:

```html
<iframe id="tyrads_iframe" src="[IFRAME_LINK]" height="650" width="300"></iframe>
```

For example:

```html
<iframe id="tyrads_iframe" src="https://sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==" height="650" width="300"></iframe>
```

## Media Source Data Sending

The authenticate method accepts additional user attributes for UTM/media-source attribution. Example request payload:

```
{
"publisherUserId": "sdk-test-full-string-ug-mqo0680t",
"age": 28,
"gender": 1,
"email": "tester@example.com",
"phoneNumber": "+14155550123",
"sub1": "sub1-value",
"sub2": "sub2-value",
"sub3": "sub3-value",
"sub4": "sub4-value",
"sub5": "sub5-value",
"userGroup": "{\"promo_affinity_ratio\":0.42,\"dynamic_payer_segment\":\"NonPayer\",\"activity_segment\":\"Tier 3\",\"seniority_segment\":\"Tier 4\",\"rewarded_video_watcher_category\":\"High\"}",
"mediaSourceName": "facebook",
"mediaSourceId": "fb-001",
"mediaSubSourceId": "fb-sub-001",
"incentivized": true,
"mediaAdsetName": "spring-campaign",
"mediaAdsetId": "adset-123",
"mediaCreativeName": "banner-a",
"mediaCreativeId": "creative-456",
"mediaCampaignName": "q2-promo",
"engagementId": 987654
}
```

**Attributes Table**

| Parameter           | Type        | Description/ Formatting                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `publisherUserId`   | String      | Specific identifier of a user for conversion tracking                                                                                                                                                                                                                                                                                                                                                   |
| `age`               | Int         | User's age (e.g. `"1-99"`                                                                                                                                                                                                                                                                                                                                                                               |
| `gender`            | Int         | User's gender (e.g. `"1-Male", "2-Female"`                                                                                                                                                                                                                                                                                                                                                              |
| `email`             | String      | User's email address                                                                                                                                                                                                                                                                                                                                                                                    |
| `phoneNumber`       | String      | User's phone number. Prefix `+` must be replaced with `00` (e.g. `0015555551234`)                                                                                                                                                                                                                                                                                                                       |
| `sub1` to `sub5`    | String      | Custom parameters for publisher tracking                                                                                                                                                                                                                                                                                                                                                                |
| `userGroup`         | JSON String | <p>Segment identifier passed as a JSON string (a stringified JSON object, not a raw JSON object).<br> \[<code>e.g. "{"promo\_affinity\_ratio":0.42,"dynamic\_payer\_segment":"NonPayer","activity\_segment":"Tier 3","seniority\_segment":"Tier 4","rewarded\_video\_watcher\_category":"High"}"</code>] <br><br><sup><code>\*\*Can be any usergroup data that you would want to pass.</code></sup></p> |
| `mediaSourceName`   | l           | Platform of acquisition (e.g. `"Facebook"`, `"Google"`)                                                                                                                                                                                                                                                                                                                                                 |
| `mediaSourceId`     | String      | Unique ID representing the media source                                                                                                                                                                                                                                                                                                                                                                 |
| `mediaSubSourceId`  | String      | Sub-source ID                                                                                                                                                                                                                                                                                                                                                                                           |
| `incentivized`      | Boolean     | If the acquisition was via incentivized networks                                                                                                                                                                                                                                                                                                                                                        |
| `mediaAdsetName`    | String      | Acquisition ad set name                                                                                                                                                                                                                                                                                                                                                                                 |
| `mediaAdsetId`      | String      | Acquisition ad set ID                                                                                                                                                                                                                                                                                                                                                                                   |
| `mediaCreativeName` | String      | Acquisition ad creative asset name                                                                                                                                                                                                                                                                                                                                                                      |
| `mediaCreativeId`   | String      | Acquisition ad creative asset ID                                                                                                                                                                                                                                                                                                                                                                        |
| `mediaCampaignName` | String      | Associated ad campaign name                                                                                                                                                                                                                                                                                                                                                                             |
| `engagementId`      | Int         | Optional engagement identifier to associate SDK activity with specific user engagements or campaigns                                                                                                                                                                                                                                                                                                    |

## Implementation of Placement ID

The placementId identifies the specific placement (ad unit) that the offerwall or widget is opened from, allowing you to track and configure performance per placement. Pass it as an argument to the iframeUrl or iframePremiumWidget methods, and the SDK appends it to the generated URL as a placementId query parameter. The optional second argument lets you deeplink to a specific route (for iframeUrl) or specify a widget name (for iframePremiumWidget). The examples below show the method calls and their resulting URLs:

```
// iframeUrl(token, null, 123)
https://v4.sdk.tyrads.com?token=demo.jwt.token&placementId=123

// iframeUrl(token, "/offers/3454", 123)
https://v4.sdk.tyrads.com?token=demo.jwt.token&to=%2Foffers%2F3454&placementId=123

// iframePremiumWidget(token, null, 123)
https://v4.sdk.tyrads.com/widget?token=demo.jwt.token&placementId=123

// iframePremiumWidget(token, "rewards", 123)
https://v4.sdk.tyrads.com/widget?token=demo.jwt.token&name=rewards-widget&placementId=123
```

## Example

For example implementation using our NodeJS SDK, you can find it here

{% embed url="<https://github.com/tyrads-com/nodejs-sdk-iframe-example/blob/main/TyrAdsSdk/index.js>" %}


# Golang

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

Integrate your Golang app with us using our Golang package

## Installation

Add `github.com/tyrads-com/tyrads-go-sdk-iframe` to your `app` as follows:

```sh
go get -u github.com/tyrads-com/tyrads-go-sdk-iframe
```

> The latest available version of Golang `github.com/tyrads-com/tyrads-go-sdk-iframe` is [v0.1.6](https://github.com/tyrads-com/tyrads-go-sdk-iframe/releases/tag/v0.1.6).

## Get Started

After successfully installing our package, create a TyrAdsSdk object with your API key and API secret:

```go
tyrAdsSdk = tyrads.NewTyrAdsSdk(
	API_KEY,
	API_SECRET,
	"") // Leave it empty ("") to use default "en" (English)
```

### Localization

This `TyrAdsSdk` class also supports localization, more info about [localization](/iframe/installation/manual-integration#localization)

For example:

```go
tyrAdsSdk = tyrads.NewTyrAdsSdk(
    API_KEY,
    API_SECRET,
    "en")
```

## Authentication

You can do the authentication by calling to our package

```go
sign, err := tyrAdsSdk.Authenticate(tyrads.AuthenticationRequest{
    PublisherUserID: PUBLISHER_USER_ID,
})
```

After obtaining the token successfully, you can call `iframeUrl` method to get the iframe URL

```go
iframeUrl, err := tyrAdsSdk.IframeUrl(token, nil)
// Result: https://sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

{% hint style="info" %}

1. A new token must be requested each time a user wants to access the offerwall.
2. Each token is valid for **7 days** only
   {% endhint %}

### Deeplinking Routes

This `iframeUrl` method also supports deeplinking, more info about [deeplinking routes](/iframe/installation/manual-integration#deeplinking-routes)

For example:

```go
deeplink := "/settings/language"
iframeUrl, err := tyrAdsSdk.IframeUrl(token, &deeplink)
// Result: https://sdk.tyrads.com?to=/settings/language&token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

### Embedding The Iframe

If your website is using html, you can add an iframe to your page to integrate TyrAds web:

```html
<iframe id="tyrads_iframe" src="[IFRAME_LINK]" height="650" width="300"></iframe>
```

For example:

```html
<iframe id="tyrads_iframe" src="https://sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==" height="650" width="300"></iframe>
```

## Example

For example implementation using our Golang SDK, you can find it here

{% embed url="<https://github.com/tyrads-com/go-sdk-iframe-example/blob/main/TyrAdsSdk/main.go>" %}


# Manual Integration

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

If your platform is not supported, you can integrate with us manually by making HTTP requests to our API using any HTTP client.

## Authentication

You can make a request to our API using any HTTP client by following the API documentation below

## POST /v4.0/initialize/auth

> Initialize SDK Session

```json
{"openapi":"3.0.4","info":{"title":"TyrAds SDK","version":"4.0.0"},"servers":[{"url":"https://api.tyrads.com"}],"paths":{"/v4.0/initialize/auth":{"post":{"tags":["default"],"summary":"Initialize SDK Session","parameters":[{"name":"lang","in":"query","schema":{"type":"string"}},{"name":"X-Api-Key","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Api-Secret","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-SDK-Platform","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-SDK-Version","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"publisherUserId":{"type":"string","description":"Publisher User/Customer unique ID","nullable":false},"age":{"type":"number","description":"User age","nullable":true},"gender":{"type":"number","description":"User gender, 1=male, 2=female","nullable":true},"email":{"type":"string","description":"User email","nullable":true},"phoneNumber":{"type":"string","description":"User phone","nullable":true},"identifierType":{"type":"string","enum":["GAID","OAID","IDFA","OTHER"],"description":"Device Identifier/Advertising ID Type","nullable":true},"identifier":{"type":"string","description":"Device Identifier/Advertising ID","nullable":true},"sub1":{"type":"string","nullable":true},"sub2":{"type":"string","nullable":true},"sub3":{"type":"string","nullable":true},"sub4":{"type":"string","nullable":true},"sub5":{"type":"string","nullable":true},"userGroup":{"type":"string","description":"Segment identifier passed as a JSON string (a stringified JSON object, not a raw JSON object).","nullable":true},"mediaSourceName":{"type":"string","nullable":true},"mediaSourceId":{"type":"string","nullable":true},"mediaSubSourceId":{"type":"string","nullable":true},"incentivized":{"type":"boolean","nullable":true},"mediaAdsetName":{"type":"string","nullable":true},"mediaAdsetId":{"type":"string","nullable":true},"mediaCreativeName":{"type":"string","nullable":true},"mediaCreativeId":{"type":"string","nullable":true},"mediaCampaignName":{"type":"string","nullable":true},"engagementId":{"type":"number","nullable":true}},"required":["publisherUserId"]}}},"required":true},"responses":{"200":{"description":"Successful operation","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"token":{"type":"string"}}},"message":{"type":"string"}}}}}},"403":{"description":"Unsuccessful operation","content":{"application/json":{"schema":{"type":"object"}}}},"422":{"description":"Unsuccessful operation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"429":{"description":"Unsuccessful operation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}}}}
```

{% hint style="info" %}

1. A new token must be requested each time a user wants to access the offerwall.
2. Each token is valid for **7 days** only
   {% endhint %}

After obtaining the token successfully, you can pass the token to our iframe link and embed the iframe on your page.

```
https://v4.sdk.tyrads.com?token=[TOKEN_HERE]
```

For example:

```
https://v4.sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==
```

### Embedding The Iframe

If your website is using html, you can add an iframe to your page to integrate TyrAds web:

```html
<iframe id="tyrads_iframe" src="[IFRAME_LINK]" height="650" width="300"></iframe>
```

For example:

```html
<iframe id="tyrads_iframe" src="https://v4.sdk.tyrads.com?token=eyJ2YWwiOiI3M3NIeUpNQlp4QzA1TlRHVzhxRExhWWNTeUQ5TTJIT0h3NXBvL3djVVp1Z09MR20wOTJJOTRReDBuYUFLeXhmVGRCaGYra2gvVGcydWFlbUh6aWR6S00vTmV0SEtVZVlWNk5Pdkc5Wnd5bytkSkxmUnA0aWt2eE9yQ01YTXF6LzBnRmZ3RUpucHMxem95WnRkYkVlQXJQNER3cDRZVkttb1lBdEIrZlB6cFZ3R25SSEE5UjROa2U2cGJTeTJod2c2UmI3UnN0QzZiN2Y2cENBYTlqaEhvQXhtdjM5UERPU2tDdWpHMmJIQ2N1cVRldVQ4a3hDSEE9PSIsInZlYyI6InNWbzZrejZRa09iS0tDeDUiLCJ0YWciOiJ1eDNnbjEwNEdUWXpvV1J2TTZVck1BPT0ifQ==" height="650" width="300"></iframe>
```

## Implementation of Placement ID

The placementId identifies the specific placement (ad unit) that the offerwall or widget is opened from, allowing you to track and configure performance per placement. Pass it as an argument to the iframeUrl or iframePremiumWidget methods, and the SDK appends it to the generated URL as a placementId query parameter. The optional second argument lets you deeplink to a specific route (for iframeUrl) or specify a widget name (for iframePremiumWidget). The examples below show the method calls and their resulting URLs:

```
// iframeUrl(token, null, 123)
https://v4.sdk.tyrads.com?token=demo.jwt.token&placementId=123

// iframeUrl(token, "/offers/3454", 123)
https://v4.sdk.tyrads.com?token=demo.jwt.token&to=%2Foffers%2F3454&placementId=123

// iframePremiumWidget(token, null, 123)
https://v4.sdk.tyrads.com/widget?token=demo.jwt.token&placementId=123

// iframePremiumWidget(token, "rewards", 123)
https://v4.sdk.tyrads.com/widget?token=demo.jwt.token&name=rewards-widget&placementId=123
```

## Deeplinking Routes

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well. Click [here](broken://pages/MKFNwkbxpNryiN9b0Cnj)

## Localization

### Overview

In addition to using URL parameters, the web application itself can change the localization settings. This allows users to switch languages directly within the application. Click [here](broken://pages/X0gL2BEg4Nc9tWOV2urd)


# Manual Integration Example Using PHP

## Using PHP CURL Extension

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

Here is the implementation example on PHP using PHP CURL Extension

{% embed url="<https://github.com/tyrads-com/php-sdk-iframe-example/blob/main/PHPCurl/index.php>" %}

### Usage Example

1. Clone the repository and open the directory
2. In `PHPCurl/index.php`, change the `$API_KEY` , `$API_SECRET` , `$AGE` , `$GENDER` , and `$PUBLISHER_USER_ID` to yours
3. Open terminal and run `php -S localhost:8000 PHPCurl/index.php`&#x20;
4. Now you can open `http://localhost:8000` on your browser

## Using PHP Guzzle Package

Here is the implementation example on PHP using PHP Guzzle

{% embed url="<https://github.com/tyrads-com/php-sdk-iframe-example/blob/main/PHPGuzzle/src/index.php>" %}

### Usage Example

1. Clone the repository and open the directory
2. In `PHPGuzzle/src/index.php`, change the `$API_KEY` , `$API_SECRET` , `$AGE` , `$GENDER` , and `$PUBLISHER_USER_ID` to yours
3. Open terminal and run `php -S localhost:8000 PHPGuzzle/src/index.php`&#x20;
4. Now you can open `http://localhost:8000` on your browser


# Manual Integration Example Using NodeJS

{% hint style="warning" %}

#### Initialize After Media Source or MMP Initialization

Please initialize our SDK only after the media source or MMP data is initialized. This ensures that the media source data is sent correctly and prevents passing empty values.
{% endhint %}

## Using Express and FetchAPI

Here is the implementation example on NodeJS using Express and FetchAPI

{% embed url="<https://github.com/tyrads-com/nodejs-sdk-iframe-example/blob/main/FetchApiExpressJS/index.js>" %}

### Usage Example

1. Clone the repository and open the directory
2. In FetchApiExpressJS`/index.js`, change the `API_KEY` , `API_SECRET` , `AGE` , `GENDER` , and `PUBLISHER_USER_ID` to yours
3. Open terminal and run `node` FetchApiExpressJS`/index.js`
4. Now you can open the `index.html` file on your browser

## Using Express and Axios

Here is the implementation example on NodeJS using Express and Axios

{% embed url="<https://github.com/tyrads-com/nodejs-sdk-iframe-example/blob/main/AxiosExpressJS/index.js>" %}

### Usage Example

1. Clone the repository and open the directory
2. In `AxiosExpressJS/index.js`, change the `API_KEY` , `API_SECRET` , `AGE` , `GENDER` , and `PUBLISHER_USER_ID` to yours
3. Open terminal and run `node AxiosExpressJS/index.js`
4. Now you can open the `index.html` file on your browser


# Overview

## 📖 Introduction

The **TyrSDK Web** is a lightweight, URL-based tool that lets you integrate our ad campaigns into your app with minimal setup and powerful monetization options.

***

{% content-ref url="/pages/MKFNwkbxpNryiN9b0Cnj" %}
[Broken mention](broken://pages/MKFNwkbxpNryiN9b0Cnj)
{% endcontent-ref %}

{% content-ref url="/pages/X0gL2BEg4Nc9tWOV2urd" %}
[Broken mention](broken://pages/X0gL2BEg4Nc9tWOV2urd)
{% endcontent-ref %}

{% content-ref url="/pages/xUXTZB4S7ewULBcVLL8o" %}
[Broken mention](broken://pages/xUXTZB4S7ewULBcVLL8o)
{% endcontent-ref %}


# Initialization

## ⚙ SDK Initialization

To initialize **Tyr SDK**, embed a URL in your **WebView** with the following structure:

```markup
https://sdk.tyrads.com?token=<TOKEN>&to=<ROUTE>&lang=<LOCALE>
```

#### 🚦 Parameters

<table><thead><tr><th width="140.18359375">Parameter</th><th width="104.90234375">Required</th><th width="363.875">Description</th><th data-type="content-ref"></th></tr></thead><tbody><tr><td><code>token</code></td><td>✅ Yes</td><td><strong>Access token generated via API</strong>. This token authenticates the session.</td><td><a href="/pages/2FqugZSqiLsUbC98PWk4">/pages/2FqugZSqiLsUbC98PWk4</a></td></tr><tr><td><code>to</code></td><td>❌ No</td><td><strong>Deep link route</strong> to direct users to a specific screen or feature in the SDK (e.g., <code>/offers</code>, <code>/active-offers</code>, <code>/settings</code>)</td><td><a href="/pages/hzsKA2qe5WOP6YqXoGlT">/pages/hzsKA2qe5WOP6YqXoGlT</a></td></tr><tr><td><code>lang</code></td><td>❌ No</td><td><strong>Language/locale code</strong> for SDK content localization. Follows ISO 639-1 (e.g., <code>en</code>, <code>ja</code>, <code>id</code>)</td><td><a href="/pages/gBb3TpIKYC0enCuSsEQX">/pages/gBb3TpIKYC0enCuSsEQX</a></td></tr><tr><td><code>skipUserInfo</code></td><td>❌ No</td><td><strong>Bypasses the user onboarding/profile collection screen on SDK launch</strong>. Set to <code>true</code> if user information has already been collected or is managed externally (e.g., <code>skipUserInfo=true</code></td><td></td></tr><tr><td><code>placementId</code></td><td>❌ No</td><td><strong>Identifies the ad placement context to filter and return only the currencies available for that specific placement.</strong> Use the placement ID assigned during your ad unit setup (e.g., <code>placementId=1</code></td><td><a href="/pages/hnBzQX89mA8mtqzwKrpQ">/pages/hnBzQX89mA8mtqzwKrpQ</a></td></tr><tr><td><code>hideBackButton</code></td><td>❌ No</td><td><strong>Hides the back button on the offerwall page, which is normally used to close the SDK.</strong> Set to <code>true</code> if you want to prevent users from closing the SDK via this button. It is usually used when close behavior is handled by your own app. (e.g., <code>hideBackButton=true</code>)</td><td></td></tr></tbody></table>

{% hint style="warning" %}
⚠️ The `token` parameter is **mandatory**. Without it, the **SDK** will not function properly.
{% endhint %}


# Deep Linking

## ⛓️‍💥 Deep Linking

The `to` parameter allows you to route users directly to a specific screen, feature, or campaign within your app.

#### 🚩 Available Deep Link Routes

<table><thead><tr><th width="244.6171875">Route</th><th>Description</th></tr></thead><tbody><tr><td><code>/offers</code> (default)</td><td>Opens the <strong>Offerwall</strong> - the default page displaying all available campaigns.</td></tr><tr><td><code>/offers/</code><mark style="color:$danger;"><code>[campaignId]</code></mark></td><td>Opens the <strong>Offer Details</strong> page for a specific campaign. Replace <mark style="color:$danger;"><code>[campaignId]</code></mark> with the campaign's unique ID.</td></tr><tr><td><code>/active-offers</code></td><td>Opens the <strong>Active Offers</strong> page, showing current ongoing campaigns.</td></tr><tr><td><code>/active-offers?groupName=</code><mark style="color:$danger;"><code>[groupId]</code></mark><code>&#x26;campaignId=</code><mark style="color:$danger;"><code>[campaignId]</code></mark></td><td>Opens the <strong>Active Offers</strong> page and sets the default selected tab and campaign. Replace <mark style="color:$danger;"><code>[groupId]</code></mark> with relevant ID (<code>HotDeals</code>, <code>UrgentTask</code>, <code>All</code>). The <mark style="color:$danger;"><code>[campaignId]</code></mark> is optional—if omitted, the first campaign in the group will be selected by default.</td></tr><tr><td><code>/support/</code><mark style="color:$danger;"><code>[campaignId]</code></mark></td><td>Opens the <strong>Support</strong> page for a specific campaign, where users can find help and FAQs. Replace <mark style="color:$danger;"><code>[campaignId]</code></mark> accordingly.</td></tr><tr><td><code>/support/</code><mark style="color:$danger;"><code>[campaignId]</code></mark><code>/not-receive-points</code></td><td>Opens the <strong>Support Ticket</strong> page for reporting missing points or other issues related to the campaign. Replace <mark style="color:$danger;"><code>[campaignId]</code></mark> with the appropriate ID.</td></tr><tr><td><code>/settings</code></td><td>Opens the <strong>Settings</strong> page where users can customize their preferences.</td></tr><tr><td><code>/settings/language</code></td><td>Opens the <strong>Language Settings</strong> page to allow users to select or change their preferred language.</td></tr></tbody></table>

{% hint style="info" %}
💡 **Pro Tip:** Replace placeholders like `[campaignId]` and `[groupId]` with actual IDs relevant to your campaigns to provide precise navigation.
{% endhint %}

#### Example Usage

You can use the following deep links by appending them to the `to` parameter:

```html
<!-- This URL will redirect the user 
to the specific offer details page for campaign ID 1234 -->

https://sdk.tyrads.com?token=<TOKEN>&to=/offers/1234
```


# Localization

## 🌎 Supported Locale Codes

Use the `lang` parameter to localize the **Tyr SDK** UI/content. Supported values follow standard **ISO 639-1** language codes:

{% hint style="success" %}
**Note:** If the `lang` parameter is not provided, the default language will be determined from the **JWT payload**.
{% endhint %}

#### 🚩 Available Languages

<table><thead><tr><th width="172.6640625">Locale Code</th><th>Language</th></tr></thead><tbody><tr><td>🇺🇸 <code>en</code></td><td>English</td></tr><tr><td>🇮🇩 <code>id</code></td><td>Indonesian</td></tr><tr><td>🇯🇵 <code>ja</code></td><td>Japanese</td></tr><tr><td>🇰🇷 <code>ko</code></td><td>Korean</td></tr><tr><td>🇪🇸 <code>es</code></td><td>Spanish</td></tr><tr><td>🇩🇪 <code>de</code></td><td>German</td></tr><tr><td>🇨🇳 <code>zh-Hans-CN</code></td><td>Chinese</td></tr><tr><td>🇫🇷 <code>fr</code></td><td>French</td></tr></tbody></table>

#### Example Usage

You can set the language of the SDK content by appending the `lang` parameter to the URL:

```html
<!-- This URL will display the SDK content in Japanese -->
https://sdk.tyrads.com?token=<TOKEN>&lang=ja
```


# Widget

The **Tyr SDK** offers multiple widgets to embed campaigns within your app, each designed for different use cases and campaign types.&#x20;

***

This widget is accessible via the `/widget` route and supports different layout:

```markup
https://sdk.tyrads.com/widget?token=<TOKEN>&name=<WIDGET_NAME>
```

### 🧩 Premium Widget

The **Premium Widget** is designed specifically to showcase **premium campaigns** within your app. It uses predefined template layouts to present these campaigns with a polished, high-quality appearance.

#### 🚩 Available Widget

<table><thead><tr><th width="181.9453125">Widget Name</th><th>Description</th><th>Example</th><th>With Currency Sales</th></tr></thead><tbody><tr><td><code>premium_1</code> (default)</td><td>Default premium widget template with standard layout.</td><td><img src="/files/1i5pLL4PvYmV1iE5MNLi" alt=""></td><td><img src="/files/hiHXCXRmE2eu2BUFgZc4" alt=""></td></tr><tr><td><code>premium_2</code></td><td>Alternative premium template with a different design.</td><td><img src="/files/GDIrOIchpzNRpOB2N6Oq" alt="" data-size="original"></td><td><img src="/files/0KG0bR2KJmHE2pXU1sVa" alt="" data-size="original"></td></tr><tr><td><code>no_offers</code></td><td>Default layout when there are no offers available</td><td><img src="/files/2d0TdpMTs76v7GKubnU1" alt="" data-size="original"></td><td></td></tr></tbody></table>

#### Example Usage

You can load the widget by using the `/widget` route and specifying a layout:

```html
<!-- This URL will load the Premium Widget using the `premium_2` layout -->
https://sdk.tyrads.com/widget?token=<TOKEN>&name=premium_2
```

### 🔎 FullScreen Integration

We're supports fullscreen mode to provide an immersive user experience. When integrated properly, the widget automatically enters fullscreen when the SDK loads.

Add the widget iframe to your page with `allowfullscreen` attribute:

```html
<iframe
  class="tyr-sdk-iframe"
  src="https://sdk.tyrads.com/widget?token=<TOKEN>&name=premium_2"
  allowfullscreen
  title="Tyr SDK Widget"
></iframe>
```

{% hint style="danger" %}
**Note:** The `allowfullscreen` attribute is required for the browser's fullscreen API to work. Without it, the widget will fall back to CSS-based fullscreen.
{% endhint %}

#### 🎨 CSS

Add these styles to your page:

```css
.tyr-sdk-iframe.fullscreen {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw !important;
  height: 100dvh !important;
  z-index: 9999;
}
```

{% hint style="info" %}
The `.fullscreen` class is used as a fallback when the browser's native fullscreen API is not available or as a CSS-based alternative.
{% endhint %}

#### 👩🏻‍💻 Javascript

Add this script to handle fullscreen communication between the widget and your page:

```javascript
// Define allowed origins for security
const allowedOrigins = ['https://sdk.tyrads.com'];

// Get all widget iframes on the page
const iframes = document.querySelectorAll('.tyr-sdk-iframe');

// Function to enter fullscreen mode
function enterFullscreen(iframe) {
  if (iframe.requestFullscreen) {
    iframe.requestFullscreen();
  } else if (iframe.webkitRequestFullscreen) {
    iframe.webkitRequestFullscreen();
  } else if (iframe.mozRequestFullScreen) {
    iframe.mozRequestFullScreen();
  } else if (iframe.msRequestFullscreen) {
    iframe.msRequestFullscreen();
  } else {
    // Fallback to CSS-based fullscreen
    iframe.classList.add('fullscreen');
  }
}

// Function to exit fullscreen mode
function exitFullscreen(iframe) {
  if (document.fullscreenElement) {
    document.exitFullscreen();
  } else if (document.webkitFullscreenElement) {
    document.webkitExitFullscreen();
  } else if (document.mozFullScreenElement) {
    document.mozCancelFullScreen();
  } else if (document.msFullscreenElement) {
    document.msExitFullscreen();
  } else {
    iframe.classList.remove('fullscreen');
  }
}

// Listen for messages from the widget
window.addEventListener('message', event => {
  // Verify message origin for security
  if (!allowedOrigins.includes(event.origin)) return;

  try {
    const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
    const sourceIframe = Array.from(iframes).find(iframe => iframe.contentWindow === event.source);
    
    if (!sourceIframe) return;

    // Handle SDK loaded event - enter fullscreen
    if (data.action === 'sdkLoaded') {
      enterFullscreen(sourceIframe);
    }

    // Handle widget loaded event - exit fullscreen
    if (data.action === 'widgetLoaded') {
      exitFullscreen(sourceIframe);
    }
  } catch (err) {
    console.error('Invalid message:', err);
  }
});

// Cleanup when user exits fullscreen manually
['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'msfullscreenchange'].forEach(eventName => {
  document.addEventListener(eventName, () => {
    if (!document.fullscreenElement && !document.webkitFullscreenElement && 
        !document.mozFullScreenElement && !document.msFullscreenElement) {
      iframes.forEach(iframe => iframe.classList.remove('fullscreen'));
    }
  });
});
```


# Currencies

## 💰Currencies

The **Tyr SDK** supports multiple virtual currencies, allowing you to display campaign rewards across different currency types that match your app's economy (e.g., coins, gems, points, tickets).

#### 💪🏼 How It Works

Each placement in your app can be associated with **one or more virtual currencies**. When a `placementId` is provided during SDK initialization, the SDK filters and returns all currencies available for that specific placement — enabling users to see and earn multiple reward types simultaneously.

If no `placementId` is provided, the SDK will fall back to the default currency configured for your account.

#### 📌 Placement-Based Multi-Currency

A single placement can expose multiple currencies at once. This is useful when your app rewards users across several in-game economies simultaneously.

**Example:** A placement can be configured to reward users in both `coins` and `gems` at the same time, so users see all applicable reward units in a single SDK session.

| Placement ID | Currencies Available           |
| ------------ | ------------------------------ |
| `1`          | 🪙 Coins                       |
| `2`          | 🪙 Coins, 💎 Gems              |
| `3`          | 🪙 Coins, 💎 Gems, 🎟️ Tickets |
| *(none)*     | Default account currency       |

{% hint style="info" %}
💡**Pro Tip:** Configure placements with multiple currencies to maximize reward relevance. Users are more engaged when they earn currencies tied directly to the in-game economy of the screen they're currently on.
{% endhint %}

#### Example Usage

Use the `placementId` parameter to load the SDK with all currencies available for that placement:

```html
<!-- Load SDK for a placement that rewards users in both Coins and Gems -->
https://sdk.tyrads.com?token=<TOKEN>&placementId=1
```

#### 🖼️ Screenshots

<figure><img src="/files/BEaw0YL69412V3j1SQbe" alt=""><figcaption></figcaption></figure>


# Reporting bugs

We hope this documentation has provided you with all the information you need. However, if you still have any questions or encounter any issues, feel free to reach out—we're happy to assist.

Before contacting us, please check the list of known issues below, as your concern might already be addressed there.

Pease provide the following details when reporting an issue to help us assist you more efficiently:

* The SDK version you are using (e.g., 2.0.1).
* Your device details, including the model (e.g., Google Pixel 3), Android version (e.g., 28), and GAID (e.g., 11111111-2222-4333-0000-7777777777).
* A clear and detailed description of the issue (the more specifics you include, the better).


# Known issues

## An Operation fails with exception "No offers available".

Your device has been blocked. If it was registered as a test device, please inform us so we can investigate and resolve the issue. Otherwise, follow these steps:

1. Uninstall the app that includes the SDK, ensuring all associated data is removed from automatic backups.
2. Reset your GAID by navigating to **Settings > Google > All Services >Ads** and selecting **Reset Ad-ID**.
3. Re-register your device as a test device using the new GAID (refer to the instructions above for guidance).

## You don't see recommended offers in the offerwall

There is 2 cases on this issue:&#x20;

* Your device has been blocked, In this case, follow the steps outlined under the  [An Operation fails with exception "No offers available.](https://app.gitbook.com/o/DuOKLqs5YxgaistFStF6/s/PEsDp5pPpMUHLOxxY7Tw/~/changes/2/questions-and-troubleshooting/known-issues#an-operation-fails-with-exception-no-offers-available)
* There are not active offers associated with your account.

## IFrame Error Messages

* **"No token was provided. Please check your request"**
* **"Your session has expired or the token provided is invalid"**

These errors occur when the **JWT token is missing or has expired**.

#### How to Resolve

* You must request a **new JWT token** from our authentication endpoint for **each user** and **each time they access the offerwall**.
* Each JWT token is valid for **7 days only**. After expiration, a new token must be generated to avoid these errors.

## IFrame Auth Endpoint Returning 403 Error Message

#### Explaination

* Our fraud prevention system blocked the user, thus the using the user id for authentication endpoint returning 403 error

#### How to Resolve

* If it is an testing account or admin user account, please kindly reach out to us for user whitelisting so that it is not blocking your testing and viewing process internally.

## <br>

<br>


# Changelog

* Unity v2.0 (Portrait Only)
  * Offerwall + Premium&#x20;
  * Localization in 4 languages&#x20;
    * Japanese&#x20;
    * Korean&#x20;
    * Spanish&#x20;
    * Bahasa

**Features and Improvements**

Published 2025-08-08

**Flutter** (**Android** & **iOS**)&#x20;

* Simplify Offerwall (server to server)
* Currency Sales
* Leveling Rewards
* Exclusion Audience
* Encryption Device Data
* Localization will automatically update at runtime<br>

<br>


# Welcome

Welcome to TyrAds SDK Documentation.

This documentation provides all the information needed to start using the TyrAds SDK libraries.


# Start Here

The Tyr SDK empowers you to seamlessly integrate our campaigns into your application, enabling you to efficiently monetize your audience with ease and effectiveness.

## Integration Requirement

### Provide Currency Icon And Currency Conversion

For you to integrate the Tyr SDK and to show the user the currency in your own native environment please provide the following details to us.&#x20;

1. Currency Icon
   1. A 50x50 icon of your own native currency
2. Currency Conversion from $1&#x20;
   1. The value of $1 in your native app currency

{% hint style="info" %}
If you use Dollars or local currency as your currency Icon and Currency conversion please notify your Tyrads Representative.&#x20;
{% endhint %}

### Request API key and secret

Before you can integrate and test the SDK with your application, you must request an API key and API secret for your app from our TyrAds Team.&#x20;

* API key is a 32 hexadecimal string
* API secret is a 92 hexadecimal string

Example of API key and API secret:

```
API_KEY=4f0abc99e38e49b8b52804116e698a45
API_SECRET=cd3c34a55a3b75a3fdd928774615d4e142dd2e6a8ce9da14df4205c7cc812ce81d3656e3dc2c0c58ed05c75c57f87a3431fed62725bb0286f9461521b6c9998b
```

{% hint style="warning" %}
Please be sure to keep your API key and secret secure! Do not share them in emails, chat messages, client-side code, or publicly accessible sites.

If you have accidentally shared an API key and secret publicly, please contact the TyrAds team to revoke it
{% endhint %}

{% hint style="info" %}
API key and API secret for integrating SDK are different from the API key and secret for Advertiser API or Publisher API
{% endhint %}

## Receiving Payouts

To be able to receive payouts for the earnings your user generates, please go to the following page for more information:

{% content-ref url="/pages/wA6KNwNFL96U0Tpn5ZNv" %}
[Postback Payout (S2S)](/v3.0/getting-started/postback-payout-s2s)
{% endcontent-ref %}

## SDK Platforms

The platforms supported by the Tyr SDK are as follows:

#### Flutter

{% content-ref url="/pages/ErwohQap4AotmCU6aZrG" %}
[Flutter](/v3.0/flutter/prerequisite)
{% endcontent-ref %}

#### Unity

{% content-ref url="/pages/9L33BUigsDiT9FYPw9sQ" %}
[Unity](/v3.0/unity/prerequisite)
{% endcontent-ref %}

#### Web / Iframe

{% content-ref url="/pages/EakABNoxl8eC1Me5vc1j" %}
[IFRAME](/v3.0/iframe/overview)
{% endcontent-ref %}


# Postback Payout (S2S)

In order for users to redeem their accumulated rewarded plays, they must be disbursed. Each reward can only be claimed once.

## Server to Server (S2S) Payout

To utilize server-to-server payout, you must establish an endpoint on your server. This endpoint will be requested by us to notify you of the user's rewards. Upon receiving the notification, it will be your responsibility to deliver it to the user.

We strongly advise implementing server-to-server payout for rewards, as it offers increased security and enhanced transparency on your part.

{% hint style="info" %}
Please contact TyrAds team and send your endpoint URL
{% endhint %}

## HTTP Request Structure

Your endpoint will be invoked via `HTTP` request with `GET` method.  The parameters of the request are as follows:

<table><thead><tr><th width="223">Paramater</th><th width="120">Data Type</th><th>Description</th></tr></thead><tbody><tr><td><code>conversion_status</code></td><td>enum</td><td>The status of conversion. Enum: <code>approved</code>, <code>rejected</code></td></tr><tr><td><code>conversion_type</code></td><td>enum</td><td>The type of conversion: Enum: <code>install</code> and <code>event</code></td></tr><tr><td><code>cost</code></td><td>decimal</td><td>The payout amount you earn from Tyrads in U.S. Dollars. </td></tr><tr><td><code>user_payout_converted</code></td><td>decimal</td><td>The payout amount the user earns based on the currency conversion set.</td></tr><tr><td><code>timestamp</code></td><td>integer</td><td>The UNIX timestamp of the conversion </td></tr><tr><td><code>publisher_user_id</code></td><td>string</td><td>The unique user id of the publisher used to identify the user</td></tr><tr><td><code>conversion_id</code></td><td>integer</td><td>The unique conversion ID can be used for deduplication if the <code>conversion_type</code> is <code>install</code> or <code>event</code>. </td></tr><tr><td><code>postback_id</code></td><td>integer</td><td>The unique postback ID can be used for deduplication. </td></tr><tr><td><code>app_name</code></td><td>string</td><td>The name of the app</td></tr><tr><td><code>event_name</code></td><td>string</td><td>The name of the event</td></tr><tr><td><code>sub3</code></td><td>string</td><td>The sub3 value, this can be any value you want and can be used to send to us on the click.</td></tr><tr><td><code>sub4</code></td><td>string</td><td>The sub4 value, this can be any value you want and can be used to send to us on the click.</td></tr><tr><td><code>ad_unit_id</code></td><td>string</td><td>The unique ad unit identifier </td></tr></tbody></table>

## Security

Verification Token

To verify the authenticity of incoming requests, kindly reach out to the TyrAds team. Upon request, we will provide you with a verification token that you can add in your postback, enabling you to confidently authenticate requests coming from our platform.

To verify the authenticity of incoming requests, kindly reach out to the TyrAds team. Upon request, we will provide you with the verification token to be added into the Postback, enabling you to authenticate data originating from our platform.

## Enhanced Security with X-Tyrads-Token

### Overview

The `X-Tyrads-Token` header provides cryptographic verification for postback requests, ensuring that data has not been tampered with and originates from TyrAds. This enhancement adds an extra layer of security beyond the basic verification token.

### How It Works

When TyrAds sends a postback to your endpoint, we include an `X-Tyrads-Token` header containing a digitally signed token. This token is generated using HMAC-SHA256 and is unique to each request.

#### Key Security Features

* **Data Integrity**: Detects any modification to URL parameters
* **Authenticity**: Verifies requests originate from TyrAds
* **Replay Protection**: Timestamp prevents reusing old tokens
* **Uniqueness**: Each token contains a unique nonce

### Token Structure

```
{version}.kid={keyId}.ts={timestamp}.nonce={nonce}.sig={signature}
```

| Component | Description                               |
| --------- | ----------------------------------------- |
| `version` | Token version (v1, v2, v3, etc.)          |
| `kid`     | Key identifier for your publisher account |
| `ts`      | Unix timestamp (seconds)                  |
| `nonce`   | 32-character hex string for uniqueness    |
| `sig`     | 64-character HMAC-SHA256 signature        |

### Setup

#### 1. Enable X-Tyrads-Token

Contact the TyrAds team to:

* Enable X-Tyrads-Token for your publisher account
* Receive your encrypted security key
* Get your key ID & Version

#### 2. Request Structure

```http
GET https://your-server.com/postback?user_id=12345&event=purchase&amount=99.99&type=event
Headers:
  X-Tyrads-Token: v1.kid=1.ts=1700000000.nonce=a1b2...sig=d4e5...
```

{% hint style="info" %}
The version prefix (v1, v2, v3, etc.) may vary. Your verification logic should handle different token versions.
{% endhint %}

### Implementation

#### Basic Verification Flow

```javascript
async function handlePostback(req, res) {
  // 1. Extract token from header
  const token = req.headers['X-Tyrads-Token'];
  
  if (!token) {
    return res.status(401).json({ error: 'Missing X-Tyrads-Token' });
  }
  
  // 2. Get full URL
  const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
  
  // 3. Verify token
  const isValid = await verifyToken(token, fullUrl);
  
  if (!isValid) {
    return res.status(403).json({ error: 'Invalid token' });
  }
  
  // 4. Process postback
  await processPostback(req.query);
  return res.status(200).json({ success: true });
}
```

#### Token Verification

The verification algorithm:

1. Parse token components (version, keyId, timestamp, nonce, signature)
2. Fetch your security key using the keyId
3. Validate timestamp (tokens older than 5 minutes are rejected) (It depends upon your needs as well,&#x20;
4. Validate nonce (ensure it hasn't been used before to prevent replay attacks)
5. Reconstruct the signing payload:
   * Extract all URL query parameters
   * Sort parameters alphabetically by key
   * Format: `param1=value1&param2=value2&ts={timestamp}&nonce={nonce}`
6. Calculate HMAC-SHA256 signature with your secret key
7. Compare signatures using timing-safe comparison

#### Node.js Verification Example

```javascript
const crypto = require('crypto');

// In-memory nonce store (use Redis or database in production)
const usedNonces = new Set();

async function verifySignedToken(token, url) {
  try {
    // Parse token
    const parts = token.split('.');
    if (parts.length !== 5 || !parts[0].startsWith('v')) {
      return false;
    }
    
    const version = parts[0];
    
    const keyId = parts[1].replace('kid=', '');
    const timestamp = parts[2].replace('ts=', '');
    const nonce = parts[3].replace('nonce=', '');
    const providedSignature = parts[4].replace('sig=', '');
    
    // Fetch your decrypted secret key (implement this based on your storage)
    const secretKey = await getSecretKey(keyId);
    if (!secretKey) return false;
    
    // Validate timestamp (reject tokens older than 5 minutes)
    const currentTimestamp = Math.floor(Date.now() / 1000);
    const tokenTimestamp = parseInt(timestamp, 10);
    const maxAgeSeconds = 300; // 5 minutes (Depends on your needs)
    
    if (isNaN(tokenTimestamp) || currentTimestamp - tokenTimestamp > maxAgeSeconds) {
      return false; // Token expired or invalid timestamp
    }
    
    // Validate nonce (prevent replay attacks)
    if (usedNonces.has(nonce)) {
      return false; // Nonce already used
    }
    
    // Extract and sort URL parameters
    const urlObj = new URL(url);
    const params = Array.from(urlObj.searchParams.entries())
      .sort((a, b) => a[0].localeCompare(b[0]))
      .map(([k, v]) => `${k}=${v}`)
      .join('&');
    
    // Reconstruct signing payload
    const payload = `${params}&ts=${timestamp}&nonce=${nonce}`;
    
    // Calculate expected signature
    const expectedSignature = crypto
      .createHmac('sha256', secretKey)
      .update(payload)
      .digest('hex');
    
    // Timing-safe comparison
    const isValid = crypto.timingSafeEqual(
      Buffer.from(expectedSignature),
      Buffer.from(providedSignature)
    );
    
    // Store nonce if valid (with TTL in production)
    if (isValid) {
      usedNonces.add(nonce);
      // Clean up expired nonces periodically
      setTimeout(() => usedNonces.delete(nonce), maxAgeSeconds * 1000);
    }
    
    return isValid;
  } catch (error) {
    console.error('Token verification error:', error);
    return false;
  }
}
```

#### PHP Verification Example

```php
<?php
// Use Redis or database in production
$usedNonces = [];

function verifySignedToken($token, $url) {
    global $usedNonces;
    
    // Parse token
    $parts = explode('.', $token);
    if (count($parts) !== 5 || strpos($parts[0], 'v') !== 0) {
        return false;
    }
    
    $version = $parts[0];
    
    $keyId = str_replace('kid=', '', $parts[1]);
    $timestamp = str_replace('ts=', '', $parts[2]);
    $nonce = str_replace('nonce=', '', $parts[3]);
    $providedSignature = str_replace('sig=', '', $parts[4]);
    
    // Fetch your secret key
    $secretKey = getSecretKey($keyId);
    if (!$secretKey) return false;
    
    // Validate timestamp (reject tokens older than 5 minutes)
    $currentTimestamp = time();
    $tokenTimestamp = intval($timestamp);
    $maxAgeSeconds = 300; // 5 minutes (Depends on your needs)
    
    if ($currentTimestamp - $tokenTimestamp > $maxAgeSeconds) {
        return false; // Token expired
    }
    
    // Validate nonce (prevent replay attacks)
    if (in_array($nonce, $usedNonces)) {
        return false; // Nonce already used
    }
    
    // Extract and sort URL parameters
    $urlParts = parse_url($url);
    parse_str($urlParts['query'], $params);
    ksort($params);
    
    $paramString = http_build_query($params);
    
    // Reconstruct signing payload
    $payload = "$paramString&ts=$timestamp&nonce=$nonce";
    
    // Calculate expected signature
    $expectedSignature = hash_hmac('sha256', $payload, $secretKey);
    
    // Timing-safe comparison
    $isValid = hash_equals($expectedSignature, $providedSignature);
    
    // Store nonce if valid
    if ($isValid) {
        $usedNonces[] = $nonce;
        // Clean up expired nonces periodically in production
    }
    
    return $isValid;
}
?>
```

#### Python Verification Example

```python
import hmac
import hashlib
import time
from urllib.parse import urlparse, parse_qs, urlencode
from typing import Set

# Use Redis or database in production
used_nonces: Set[str] = set()

async def verify_signed_token(token: str, url: str) -> bool:
    try:
        # Parse token
        parts = token.split('.')
        if len(parts) != 5 or not parts[0].startswith('v'):
            return False
        
        version = parts[0]
        
        key_id = parts[1].replace('kid=', '')
        timestamp = parts[2].replace('ts=', '')
        nonce = parts[3].replace('nonce=', '')
        provided_signature = parts[4].replace('sig=', '')
        
        # Fetch your secret key
        secret_key = await get_secret_key(key_id)
        if not secret_key:
            return False
        
        # Validate timestamp (reject tokens older than 5 minutes)
        current_timestamp = int(time.time())
        token_timestamp = int(timestamp)
        max_age_seconds = 300  # 5 minutes (Depends on your needs)
        
        if current_timestamp - token_timestamp > max_age_seconds:
            return False  # Token expired
        
        # Validate nonce (prevent replay attacks)
        if nonce in used_nonces:
            return False  # Nonce already used
        
        # Extract and sort URL parameters
        parsed = urlparse(url)
        params = parse_qs(parsed.query)
        # Flatten single-value lists and sort
        flat_params = {k: v[0] if len(v) == 1 else v for k, v in params.items()}
        sorted_params = urlencode(sorted(flat_params.items()))
        
        # Reconstruct signing payload
        payload = f"{sorted_params}&ts={timestamp}&nonce={nonce}"
        
        # Calculate expected signature
        expected_signature = hmac.new(
            secret_key.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        
        # Timing-safe comparison
        is_valid = hmac.compare_digest(expected_signature, provided_signature)
        
        # Store nonce if valid
        if is_valid:
            used_nonces.add(nonce)
            # Clean up expired nonces periodically in production
        
        return is_valid
    except Exception as e:
        print(f"Token verification error: {e}")
        return False
```

### FAQ

<details>

<summary>Is X-Tyrads-Token required?</summary>

While not mandatory, it's **strongly recommended** for enhanced security. Contact the TyrAds team to enable it for your account.

</details>

<details>

<summary>How often should I rotate my security key?</summary>

It depends on you if you want to rotate after n number of days. Same can be communicated to Tyrads

</details>

<details>

<summary>Can the same token be used twice?</summary>

No. Each token contains a unique nonce and timestamp. You should track used nonces (with TTL matching your timestamp validation window) to reject duplicate requests. Reusing tokens indicates a potential replay attack.

</details>

<details>

<summary>What if my key is compromised?</summary>

Immediately contact the TyrAds,   to deactivate the compromised key and issue a new one.

</details>

{% hint style="info" %}
For security key setup or issues, please reach out to the TyrAds team directly.
{% endhint %}


# Tyrads Whitelist IP Addresses

This section provides the IPv4 addresses for Tyrads publisher postback service for your whitelisting purposes.

### Tyrads Publisher Postback IP Addresses

**IPv4 Address:**

```
3.84.56.180 
```

```
34.227.70.236 
```

```
52.202.96.227 
```

For more question, please contact your TyrAds administrator or integration team.

Last Updated: June 09, 2026


# SDK Integration Checklist

To ensure a seamless SDK integration and maximize performance, please review this checklist. It covers essential best practices, parameter mappings, and required feature utilization.

<table><thead><tr><th width="164.37890625">Feature/ Parameter</th><th>Checklist Question</th><th>Recommendation / Action</th><th>Explanation</th></tr></thead><tbody><tr><td>Initialization</td><td>When are you initializing our SDK in your app?</td><td>Initialize during app launch/open, preferably after Mobile Media Partner (MMP) initialization (if any).</td><td>We recommend initializing our SDK during app launch, ideally after MMP initialization (if any).</td></tr><tr><td>Media Source Data</td><td>Are you passing media source data to us?</td><td><a data-mention href="/pages/sQLb6rC5ziweGZOyKpz8">/pages/sQLb6rC5ziweGZOyKpz8</a></td><td>Send media data of where you acquired the users to our system. We will use this in our systems to be able to segment the user base and provide media-source-specific rewards.</td></tr><tr><td>Postback Setup</td><td>Are the postback macros setup and working correctly as intended?</td><td>Ensure that postbacks are received correctly on your server.</td><td>To ensure postback data is passed correctly to your end for user rewards.</td></tr><tr><td><p></p><p>Currency Conversion and Ad Unit settings</p></td><td>Are the media asset and ad unit settings correct?</td><td>Ensure that currency conversion and user margins are set up correctly in the ad unit in the Solutions dashboard.</td><td>Ensures currency conversion and user margins are accurate during user rewards and payouts.</td></tr><tr><td><p></p><p>Decimals in rewards</p></td><td>Does your system/server/app accept decimals in the user reward currency?</td><td>Please inform the <strong>TyrAds integration team</strong> about this.</td><td>We have settings that can be enabled to round user rewards to whole numbers.</td></tr></tbody></table>


# Advanced options


# Sending Media Source Data

Send media data of where you acquired the users to our system, we will use this in our systems to be able to segment the user base and proved media source specific rewards.&#x20;

{% hint style="info" %}
This is related to intialization of the SDK.&#x20;
{% endhint %}

{% hint style="warning" %}
**Other than mediaSourceName which is mandatory, others are optional.** However, it is highly recommended to provide us all these data for us to tailor the rewards journey towards different media sources.&#x20;
{% endhint %}

<table><thead><tr><th width="223">Paramater</th><th width="120">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>mediaSourceName [<strong>Mandatory]</strong></td><td>string</td><td>Can be used to send the source name of where you got the user </td></tr><tr><td>mediaCampaignName</td><td>string</td><td>Can be used to send the campaign name of where you got the user</td></tr><tr><td>mediaSourceId</td><td>string</td><td>Can be used to send the source id of where you got the user</td></tr><tr><td>mediaSubSourceId</td><td>string</td><td>Can be used to send the Sub Source id of where you got the user</td></tr><tr><td>Incentivized</td><td>boolean</td><td>Can be used to send if the user acquisition was done via incent channels or non incent channels.</td></tr><tr><td>mediaAdsetName</td><td>string</td><td>Can be used to send the adset name of where you got the user</td></tr><tr><td>mediaAdsetId</td><td>string</td><td>Can be used to send the adset id of where you got the user</td></tr><tr><td>mediaCreativeName</td><td>string</td><td>Can be used to send the CreativeName of where you got the user</td></tr><tr><td>mediaCreativeId</td><td>string</td><td>Can be used to send the creativeId of where you got the user</td></tr><tr><td>sub1</td><td>string</td><td>Can use this to to store any type of data. <br><br>Currently only used to store data can't be received on the postback</td></tr><tr><td>sub2</td><td>string</td><td>Can use this to to store any type of data. <br><br>Currently only used to store data can't be received on the postback</td></tr><tr><td>sub3</td><td>string</td><td>Can use this to store any type of data. And can be sent back on the postback as well.<br><br><a data-mention href="/pages/wA6KNwNFL96U0Tpn5ZNv">/pages/wA6KNwNFL96U0Tpn5ZNv</a></td></tr><tr><td>sub4</td><td>string</td><td>Can use this to store any type of data. And can be sent back on the postback as well.<br><br><a data-mention href="/pages/wA6KNwNFL96U0Tpn5ZNv">/pages/wA6KNwNFL96U0Tpn5ZNv</a></td></tr><tr><td>sub5</td><td>string</td><td>Can use this to to store any type of data. <br><br>Currently only used to store data can't be received on the postback</td></tr></tbody></table>


# Sending User Segments / User Info

Sending user segments to our system will allow our system to be able to segment the userbase within the segments you use on your side. Aswell it will allow us to use this information to detect fraudulent users.&#x20;

{% hint style="info" %}
This is related to intialization of the SDK&#x20;
{% endhint %}

{% hint style="warning" %}
This is not required, but allows us to be able to indentify fraudulents user based on email/phone numbers.&#x20;
{% endhint %}

| Paramater       | Data Type   | Description                                                                                                                                                            |
| --------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| userPhoneNumber | Integer     | <p>Can be used to identify the user to prevent fraud. <br><br>Format the + as  00, example: 0015555551234 for a US number</p>                                          |
| userEmail       | email       | Can be used to identify the user to prevent fraud                                                                                                                      |
| userGroup       | JSON string | <p>Can be used to segment the user base in different groups allowing you to reward them a higher or lower % based on this group.<br>Example (High purchasing user)</p> |


# Prerequisite

* Unity version 2021.3.45 or higher
* Android SDK 24 or higher using Google Play Services
* iOS version 12.0 or higher


# Installation

The **TyrAds Unity SDK** available from a Git URL. To install:

1. Open the ***Package Manager*** window in Unity, if it’s not already open.
2. Open the ***Add (+)*** menu in the Package Manager’s toolbar.
3. Select ***Install package from git URL*** from the install menu.
4. Enter a Git URL in the text box:\
   `https://github.com/tyrads-com/tyrads-unity-sdk-package.git`&#x20;
5. Select \`***Install***\`.

<figure><img src="/files/3ut5O1ATnKKhlTuHWMxB" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you want to check for updates and update **TyrAds Unity SDK** dependency to the latest version from the repository, click ***Update*** in the ***Package Manager*** window.
{% endhint %}

If you want to install a certain version of the **TyrAds Unity SDK** you can specified a version in the Git URL (example):

```
https://github.com/tyrads-com/tyrads-unity-sdk-package.git#v4.0.0-pre.2
```

To explore how to use the TyrAds Unity SDK, import the *Demo* example from the package’s Samples section in the Unity Package Manager.

### Required Android Permissions

To ensure proper SDK functionality, configure your main AndroidManifest.xml at:

```
Assets/Plugins/Android/AndroidManifest.xml
```

&#x20;You can either:

* Copy the reference manifest as your main file from Assets/Plugins/TyrAdsSDK/AndroidManifestReference/AndroidManifest.xml, or
* Add the following permissions manually to your existing manifest:

```xml
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
                 tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE" />
<service android:name=".BackgroundService" android:enabled="true" android:exported="false" />
    <receiver android:name="com.adjust.sdk.AdjustReferrerReceiver" android:permission="android.permission.INSTALL_PACKAGES" android:exported="true">
      <intent-filter>
        <action android:name="com.android.vending.INSTALL_REFERRER" />
      </intent-filter>
    </receiver>
```

**Important Notes:**

* **Placement:** Add the permissions **inside the `<manifest>` tag but outside the `<application>` tag**.
* **Manual Integration:** These permissions are **not added automatically** due to a conflict with main `AndroidManifest` Make sure to insert them manually.
* **Minimum SDK Requirements:**
  * `QUERY_ALL_PACKAGES` and `PACKAGE_USAGE_STATS` may require your app to target **API level 30+**.
  * Google Play may require justification for using `QUERY_ALL_PACKAGES`.


# Version 4.0.0-beta

## Installation

The **TyrAds Unity SDK** available from a Git URL. To install:

1. Open the ***Package Manager*** window in Unity, if it’s not already open.
2. Open the ***Add (+)*** menu in the Package Manager’s toolbar.
3. Select ***Install package from git URL*** from the install menu.
4. Enter a Git URL in the text box:\
   `https://github.com/tyrads-com/tyrads-unity-sdk-package.git#v4.0.0-pre.2`&#x20;
5. Select \`***Install***\`.

To explore how to use the TyrAds Unity SDK, import the *Demo* example from the package’s Samples section in the Unity Package Manager. To run a Demo scene, please add at least one session configuation with one of the id: Coin, Diamond or Crystal.&#x20;

## Initialization

To initializes the **TyrAds Unity SDK** you must provide the necessary credentials obtained from the TyrAds platform. These credentials allow your application to establish secure communication with the TyrAds' backend services.

#### a. Adding Credentials via the Editor&#x20;

After importing the SDK, follow these steps to configure it in your project:

* **Open the Configuration Window**
  * Navigate to **TyrSDK > TyrSDK Settings** to access the **TyrSDK Settings** panel.
* **Manage Session Credentials**

  The settings panel allows you to create and configure multiple session entries. Each entry includes:&#x20;

  * **Unique Identifier**: A string used to reference this session configuration.&#x20;
  * **API Key**: A 32-character hexadecimal string (Mandatory. Provided by TyrAds).&#x20;
  * **API Secret**: A 92-character hexadecimal string (Mandatory. Provided by TyrAds).&#x20;
  * **Encryption Key**: A 32-character hexadecimal string (Optional. Provided by TyrAds).

<figure><img src="/files/GKSroxigmc64kVx0y8mF" alt=""><figcaption></figcaption></figure>

You can add or remove session entries using the **+/–** buttons. All configured sessions will be available to the SDK at runtime.

#### b.  Adding Credentials via the Code

You can initialize credentials programmatically. Two methods are available depending on your needs:

**Initialize a Single Session**

If your application uses only one session configuration, you can initialize it directly:

```csharp
TyrSDKPlugin.Instance.Init("API_KEY", "API_SECRET", "ENCRYPTION_KEY");
```

**Initialize Multiple Sessions**

For applications that require multiple session configurations, use:

```csharp
var sessions = new[]
{
    new SessionConfig("session_1","API_KEY_1","API_SECRET_1","ENCRYPTION_KEY_1"),
    new SessionConfig("session_2","API_KEY_2","API_SECRET_2","ENCRYPTION_KEY_2")
};

TyrSDKPlugin.Instance.Init(sessions);
```

Each **SessionConfig** entry corresponds to one set of credentials, matching the format used in the editor.

**Notes**

* When using multiple sessions, ensure that any operation requiring authentication references the correct unique identifier.&#x20;
* If both Editor-configured sessions and code-based initialization are used, programmatic initialization will override editor settings at runtime unless documented otherwise.&#x20;
* Make a **Init** call before making a **LoginUser** call to ensure that your credentials are properly set before the initialization process begins.

#### Using Different Credentials for Android and iOS

In some projects, you may need to initialize the SDK with different credentials per platform (e.g., separate API keys for iOS and Android).

Editor-based configuration does not support platform-specific credentials, this type of configuration cannot be handled through the Settings Editor window.

To support platform-specific credentials, you must use the code-based initialization approach.

On the developer side, the application should detect the active platform at runtime and provide the correct credentials accordingly.

Below is a simple example demonstrating how to configure this:

<pre class="language-csharp"><code class="lang-csharp">#if UNITY_ANDROID
var config = new SessionConfig(
    uniqIdentifier: "coin",
    apiKey: "ANDROID_API_KEY",
    apiSecret: "ANDROID_API_SECRET",
    encryptionKey: "ANDROID_ENCRYPTION_KEY"
);
#elif UNITY_IOS
var config = new SessionConfig(
    uniqIdentifier: "coin",
    apiKey: "IOS_API_KEY",
    apiSecret: "IOS_API_SECRET",
    encryptionKey: "IOS_ENCRYPTION_KEY"
);
#else
//default credentials could be used for the editor test run
var config = new SessionConfig(
    uniqIdentifier: "coin",
    apiKey: "DEFAULT_API_KEY",
    apiSecret: "DEFAULT_API_SECRET",
    encryptionKey: "DEFAULT_ENCRYPTION_KEY"
);
#endif

<strong>TyrSDKPlugin.Instance.Init(new[] { config });
</strong></code></pre>

### Configure SDK Initialization Wizard

By default TyrAds SDK before open any offers page show initialization wizard, where user could read and accept TyrAds Privacy Policy, give acess to usege stats permit (only on Android) and provide information about age and gender. You able to disable presentation of the privacy policy and usege stats permit pages.&#x20;

To do that follow next steps:

* Navigate to **TyrSDK > TyrSDK Settings** to access the **TyrSDK Settings** panel.
* Switch to **Settings** tab.
* Switch toggles for 'Show Privacy Policy Page' and 'Show Usage Stats Permit Page'.

<figure><img src="/files/3fLDzp6fyQGwso7eJnLT" alt=""><figcaption></figcaption></figure>

### User Login

Upon initializing the SDK, the mandatory step is to log in the user. However, passing a user ID is optional and is only necessary when the publisher operates its own user system. This login process ensures that user interactions with the offerwall are accurately tracked and attributed within the application.

{% hint style="warning" %}

* If you do not provide a user ID, it will be generated automatically and stored in app storage. In that case, uninstalling the app will erase the ID and the user’s progress.
* **Preferred: supply a backend-controlled, stable user ID (or equivalent) so progress persists across reinstalls and device changes.** await TyrSDKPlugin.Instance.LoginUserAsync(userId); /
  {% endhint %}

To determine when initialization has completed and to identify which session ID was used, you can await the login operation and read the relevant data from the returned **LoginResult**:

```csharp
LoginData loginData = new LoginData(userId);
LoginResult result = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);

if (result.IsSuccessful)
{
   //do anything what you want after successful init...
   //a list of id for successfully initialized session could be get from result.InitializedSessions 
}
```

You can retrieve the generated user ID after successful initialization by calling the following method:

<pre class="language-csharp"><code class="lang-csharp"><strong>var userId = TyrSDKPlugin.Instance.GetUserId();
</strong></code></pre>

#### Advanced Practices for personalized rewards

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

To maximize the value of our Tyr SDK please follow the advanced options for user login. This will allow us to personalize the rewards for the user event further and maximize the earnings for you as publisher.&#x20;

<pre class="language-csharp"><code class="lang-csharp"><strong>var userInfo = new TyradsUserInfo(
</strong>    userPhoneNumber: "+1234567890",
    userEmail: "demo@example.com",
    userGroup: "premium_users"
);

var mediaSourceInfo = new TyradsMediaSourceInfo(
    mediaSourceName: "Facebook", //mandatory
    mediaCampaignName: "Summer Sale Campaign",
    mediaSourceId: "fb_123",
    mediaSubSourceId: "fb_sub_456",
    incentivized: true,
    mediaAdsetName: "Summer Sale Adset",
    mediaAdsetId: "adset_789",
    mediaCreativeName: "Summer Sale Creative",
    mediaCreativeId: "creative_101",
    sub1: "campaign_source",
    sub2: "ad_group",
    sub3: "creative_type",
    sub4: "placement",
    sub5: "custom_param"
);

var engagementInfo = new TyradsEngagementInfo(
    engagementId: 12345  // Optional: Unique identifier for tracking user engagement
);

LoginData loginData = new LoginData(userId, userInfo, mediaSourceInfo, engagementInfo);
LoginResult result = await TyrSDKPlugin.Instance.LoginUserAsync(loginData);
</code></pre>

### Show Offerwall

Once the SDK is initialized and the user is logged in (if applicable), you can display the offerwall to the user. This typically involves calling a function provided by the Tyrads SDK, such as showOffers, passing in the context of your application. The offerwall is where users can engage with various offers, advertisements, or promotions provided by Tyrads, potentially earning rewards or incentives in the process.

```csharp
// Note: Campaigns Page is the default route when no specific route is provided
TyrSDKPlugin.Instance.ShowOffers();
```

If you want to display offers for a specific session, you must provide its identifier in the OffersRoutingData parameter.

```csharp
OffersRoutingData offersRoutingData = new OffersRoutingData("session_2"); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);
```

Also, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well. Available routes and their usage:

* `TyradsDeepRoutes.Offers` - opens the Campaigns Page
* `TyradsDeepRoutes.ActiveOffers` - opens the Activated Campaigns Page
* `TyradsDeepRoutes.Offer` - opens the Campaign Details Page (requires campaignID)
* `TyradsDeepRoutes.Support` - opens the Campaign Tickets Page (requires campaignID)

```csharp
//Use TyradsDeepRoutes class to avoid typos
OffersRoutingData offersRoutingData = new OffersRoutingData("session_2", TyradsDeepRoutes.Offers); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);

//Specify a route and campaignID
OffersRoutingData offersRoutingData = new OffersRoutingData("session_2", TyradsDeepRoutes.Offer, 111); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);

//If you use only one session, you can set empty string for sessionID
OffersRoutingData offersRoutingData = new OffersRoutingData(string.Empty, TyradsDeepRoutes.ActiveOffers); 
TyrSDKPlugin.Instance.ShowOffers(offersRoutingData);
```

### Premium Widget

The Premium Widget displays offers based on the active session. To change the active session, call:

```csharp
TyrSDKPlugin.Instance.SwitchToSession("session_2");
```


# Initialization

Integrating the TyrAds offerwall functionality into your application is a straightforward process that involves a few key steps. By following these integration steps, you can seamlessly incorporate the offerwall feature, enhancing user engagement and potentially generating additional revenue for your application.

{% hint style="success" %}

### SDK Initialization best practices:

* **Initiate early:** It's advisable to initialize the SDK promptly after your app launches to ensure that all Tyr SDK functionalities are accessible when needed.
* **Initiate authentication:** Login to the SDK with current user details immediately after your user signs up or signs in to the app to set the `userId`.
  {% endhint %}

For guidance on integrating TyrSDK - including proper initialization and offer display - see the example at `Sample -> Demo`:

### 1. Scene setup

Add the **TyrSDKPlugin** prefab to your initial scene:

```
Packages/com.tyrads.unity-sdk/Runtime/Prefabs/TyrSDKPlugin.prefab
```

This enables API access via SDKPlugin.Instance in code.

### 2. **Initialization**

This step initializes the Tyrads SDK within your application. You need to provide the API key and API secret obtained from the Tyrads platform. This allows your app to communicate securely with Tyrads' servers.

#### a. Adding Credentials via the Editor&#x20;

Once **TyrSDK** is imported, follow these steps to configure it for your project:

* **Open the Configuration Window**
  * Navigate to **TyrSDK > TyrSDK Settings** to access the **TyrSDK Settings** panel.
* **Enter Your Credentials**
  * **API Key:** A **32-character** hexadecimal string.
  * **API Secret:** A **92-character** hexadecimal string.
  * **Encryption Key:** A **32**-**character** hexadecimal string.

<figure><img src="/files/tkiFXG0Q2OukGyL4wdAU" alt="" width="563"><figcaption></figcaption></figure>

#### b.  Adding Credentials via the Code

Make a call:

```csharp
TyrSDKPlugin.Instance.Init("API_KEY", "API_SECRET", "ENCRYPTION_KEY");
```

**before** making a LoginUser call. This ensures that your credentials are properly set before the initialization process begins.

#### Using Different Credentials for Android and iOS&#x20;

In some projects, you may need to initialize the SDK with different credentials per platform (e.g., separate API keys for iOS and Android).

Editor-based configuration does not support platform-specific credentials, this type of configuration cannot be handled through the Settings Editor window.

To support platform-specific credentials, you must use the code-based initialization approach.

On the developer side, the application should detect the active platform at runtime and provide the correct credentials accordingly.

Below is a simple example demonstrating how to configure this:

```csharp
//default credentials could be used for the editor test run
string apiKey = "DEFAULT_API_KEY";
string apiSecretv = "DEFAULT_API_SECRET";
string encryptionKey = "DEFAULT_ENCRYPTION_KEY";

#if UNITY_ANDROID
  apiKey = "ANDROID_API_KEY";
  apiSecretv = "ANDROID_API_SECRET";
  encryptionKey = "ANDROID_ENCRYPTION_KEY";
#elif UNITY_IOS
  apiKey = "IOS_API_KEY";
  apiSecretv = "IOS_API_SECRET";
  encryptionKey = "IOS_ENCRYPTION_KEY";
#endif

TyrSDKPlugin.Instance.Init(apiKey, apiSecret, encryptionKey);
```

### 3. User Login

Upon initializing the SDK, the mandatory step is to log in the user. However, passing a user ID is optional and is only necessary when the publisher operates its own user system. This login process ensures that user interactions with the offerwall are accurately tracked and attributed within the application.

```csharp
TyrSDKPlugin.Instance.LoginUser(userId); //userID is optional
```

{% hint style="warning" %}

* If you do not provide a user ID, it will be generated automatically and stored in app storage. In that case, uninstalling the app will erase the ID and the user’s progress.
* **Preferred: supply a backend-controlled, stable user ID (or equivalent) so progress persists across reinstalls and device changes.**&#x20;
  {% endhint %}

To receive the initialization completion result, subscribe to the event before calling LoginUser:

```csharp
TyrSDKPlugin.Instance.InitializationCompleted += OnSdkInitializationCompleted;

...

private void OnSdkInitializationCompleted(bool isSuccess)
{
    // your code here
}
```

If you don’t set a user ID in LoginUser, you can retrieve the generated user ID after successful initialization by calling the following method:

<pre class="language-csharp"><code class="lang-csharp"><strong>var userId = TyrSDKPlugin.Instance.GetUserId();
</strong></code></pre>

#### 3.1 Advanced Practices for personalized rewards

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

To maximize the value of our Tyr SDK please follow the advanced options for user login. This will allow us to personalize the rewards for the user event further and maximize the earnings for you as publisher.&#x20;

<pre><code><strong>var userInfo = new TyradsUserInfo(
</strong>    userPhoneNumber: "+1234567890",
    userEmail: "demo@example.com",
    userGroup: "premium_users"
);

var mediaSourceInfo = new TyradsMediaSourceInfo(
    mediaSourceName: "Facebook", //mandatory
    mediaCampaignName: "Summer Sale Campaign",
    mediaSourceId: "fb_123",
    mediaSubSourceId: "fb_sub_456",
    incentivized: true,
    mediaAdsetName: "Summer Sale Adset",
    mediaAdsetId: "adset_789",
    mediaCreativeName: "Summer Sale Creative",
    mediaCreativeId: "creative_101",
    sub1: "campaign_source",
    sub2: "ad_group",
    sub3: "creative_type",
    sub4: "placement",
    sub5: "custom_param"
);

var engagementInfo = new TyradsEngagementInfo(
    engagementId: 12345  // Optional: Unique identifier for tracking user engagement
);

TyrSDKPlugin.Instance.LoginUser(userId, userInfo, mediaSourceInfo, engagementInfo);
</code></pre>

[Sending Media Source Data](/v3.0/getting-started/advanced-options/sending-media-source-data)

[Sending User Segments / User Info](/v3.0/getting-started/advanced-options/sending-user-segments-user-info)

### 4. Show Offerwall

Once the SDK is initialized and the user is logged in (if applicable), you can display the offerwall to the user. This typically involves calling a function provided by the Tyrads SDK, such as showOffers, passing in the context of your application. The offerwall is where users can engage with various offers, advertisements, or promotions provided by Tyrads, potentially earning rewards or incentives in the process.

```csharp
TyrSDKPlugin.Instance.ShowOffers();
```

#### 4.1 Deeplinking Routes

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well. Available routes and their usage:

* TyradsDeepRoutes.Offers - opens the Campaigns Page
* TyradsDeepRoutes.ActiveOffers - opens the Activated Campaigns Page
* TyradsDeepRoutes.Offer - opens the Campaign Details Page (requires campaignID)
* TyradsDeepRoutes.Support - opens the Campaign Tickets Page (requires campaignID)

```
//Use TyradsDeepRoutes class to avoid typos
TyrSDKPlugin.Instance.ShowOffers(TyradsDeepRoutes.Offers);

//Specify a route and campaignID
TyrSDKPlugin.Instance.ShowOffers(TyradsDeepRoutes.Offer, campaignId: 111);
```


# Premium Offers

The **Premium Widget** is a UI element that becomes available after SDK initialization. It is independent of the SDK itself and can be dragged into any **Canvas** within your application.

\
The **Premium Widget** provides seamless access to various offerwall features:

* **More Offers** – Opens the full offerwall.
* **Active Offers** – Displays active offers.
* **Campaign record** - Open the page with campaign details. &#x20;
* **Play** – Activate campaign and redirects users to the store.

This widget enhances user engagement by integrating smoothly within your game's UI.

#### Available Widget Style options

The widget style is set via the `visualizationType` property of the `PremiumWidget` component on the **PremiumWidget** prefab.

The default style is `PremiumWidgetVisualizationType.ListView`, which displays the offers in a list.

Other available style is `PremiumWidgetVisualizationType.SlideCards`, which displays the offers in a cards slider.

You can also toggle the widget’s visibility in code during run time:

```
TyrSDKPlugin.Instance.SetPremiumWidgetStyle(visualStyle); //where visualStyle is PremiumWidgetVisualizationType.ListView or PremiumWidgetVisualizationType.SlideCards
```

<figure><img src="/files/zZYyDZa9mCU3m1FVM952" alt="List View"><figcaption><p>List View</p></figcaption></figure>

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt="Card View"><figcaption><p>Card View</p></figcaption></figure>

## Setting Up the Premium Widget

To integrate the **Premium Widget** into your application, navigate to PremiumWidget prefab:

```
Packages/com.tyrads.unity/Runtime/Prefabs/PremiumWidget/PremiumWidget.prefab
```

Drag the **PremiumWidget** prefab into Canvas on your scene.

*Game UI with integrated Premium Widget*:

<figure><img src="/files/JRhdRfzNizJudcZGHV35" alt="" width="563"><figcaption></figcaption></figure>


# Change Language

Use the following to change the TyrAds SDK language and update its internal locale settings:

```csharp
TyrSDKPlugin.Instance.SetLanguage("en");
```

#### Parameters:

* `languageCode` (string): A string representing the desired language code (e.g., "en" for English, "es" for Spanish). This should be a valid ISO 639-1 language code. \
  Supported languages: English (en), Spanish (es), Indonesian (id), Japanese (ja), Korean (ko), Chinese Simplified (zh-Hans-CN).

#### Notes:

* By default, the TyrAds SDK uses the device’s system language.
* This method saves the selected language in shared preferences so it persists across sessions.
* Ensure your app and the TyrAds SDK support the provided language code; otherwise, English will be used.


# Obtaining Advertising ID's

**Android 12+**

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the `AndroidManifest.xml` file.

Navigate to the `Assets/Plugins/Android/AndroidManifest.xml` inside your project, locate the `AndroidManifest.xml` file and add the following line just before the `<application>`.

```
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
```

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248).

**iOS 14+**

`NSUserTrackingUsageDescription` should be added to `Info.plist` file like

```
<key>NSUserTrackingUsageDescription</key><string>
```

The SDK includes a Unity build post-process that adds this to the build’s `Info.plist` .&#x20;

Request IDFA Permission&#x20;

Tyrads SDK can work with or without the IDFA permission on iOS 14+. If no permission is granted in the ATT popup, the SDK will serve non personalized offers to the user. In that scenario the conversion is expected to be lower. Offerwall integrations perform better compared to when no IDFA permission is given. Our recommendation is that you should ask for IDFA usage permission prior to TyrAds SDK initialization.<br>


# Migration guide to v3.1.0 or newer

## Migrating from TyrAds SDK v3.0 (.unitypackage) to v3.1.0 or newer (UPM)

This guide walks you through upgrading a project that previously used the v3.0 .unitypackage to the new v3.1.0 or newer package distributed via the Unity Package Manager (UPM).

Before you start

* Commit or back up your project.
* Close running play sessions and save all open scenes.

***

### 1) Remove the old v3.0 installation

The .unitypackage installed files directly under your Assets/ folder. To avoid duplicate symbols and GUID conflicts, remove the old content completely.

Default folder path:

```
Assets/Plugins/TyrAdsSDK/. //Path could be if differ if your team have moved sdk
```

***

### 2) Install latests (v3.1.0 or newer) package via the Unity Package Manager (UPM)

Follow the steps from [Installation](/v3.0/unity/installation) page.

After installation, you should see TyrAds Unity SDK under Packages/ in the Project window.

***

### 3) Verify & refresh scene references

Because the UPM package provides new prefab and script GUIDs, references from the old .unitypackage may be missing. Open your main scenes and fix any missing references.

#### 3.1 Main SDK object on the scene

* Look for your previous TyrSDKPlugin object.
* If the component shows Missing (Mono Script) or a broken reference:
  1. Remove the broken component/prefab instance.
  2. Locate the new prefab in the package folder

     <kbd>Packages/com.tyrads.unity-sdk/Runtime/Prefabs/TyrSDKPlugin.prefab</kbd>.
  3. Drag the new prefab into your scene.
  4. Reapply any scene-specific settings you previously had.

#### 3.2 Premium widget prefab

* Find any UI locations where the premium widget was used.
* If you see a Missing (Prefab) or Missing (Mono Script):
  1. Remove the broken reference.
  2. Locate the new prefab in the package folder

     <kbd>Packages/com.tyrads.unity/Runtime/Prefabs/PremiumWidget/PremiumWidget.prefab</kbd> .
  3. Drag the new premium widget prefab into your scene.
  4. Reconnect it to your UI hierarchy and set its properties as needed.

***

### 4) Reapply configuration (only if you used the SDK editor window)

* If you previously configured the SDK via its Editor Window (e.g., entering app ids/keys, toggles, or project-wide settings):
  * Open the new TyrAds Settings&#x20;

    **TyrSDK > TyrSDK Settings**.
  * Re-enter your configuration values as before.
* If your configuration is set programmatically (in code):
  * No extra steps needed. Your code-based configuration should continue to work after you fix script/component references.

***

### 5) Clean up and validate

1. Save all modified scenes.
2. Enter Play Mode and validate:
   * Initialization logs appear without errors.
   * The premium widget renders and behaves as expected.
   * Ads/placements load and show as before (in appropriate test/dev environments).

***

### Troubleshooting

* Duplicate class/namespace or redefinition errors:

  You still have old .cs files under Assets/. Recheck step 1 and remove any leftovers.
* Missing script on a prefab after install:

  Replace the instance with the new prefab from the UPM package (see step 3).
* Editor window/menu not found:

  Ensure v3.1.0 or newer is installed under Packages/ and re-open Unity if needed. Some editor menus appear after a domain reload.

***

### Quick Checklist

* Old TyrAds folders removed from Assets/ (default or any custom locations)
* TyrAds SDK v3.1.0 or newer installed via UPM
* Main SDK scene object replaced/verified
* Premium widget prefab replaced/verified
* Configurations re-applied (only if previously set in editor)
* Play Mode sanity test passed


# Prerequisite

* Min Android SDK 24 or higher using Google Play Services


# Installation

Step 1. Add the JitPack repository to your build file&#x20;

Add it in your root build.gradle at the end of repositories:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            mavenCentral()
            maven { url 'https://jitpack.io' }
        }
    } 
```

{% endtab %}

{% tab title="Groovy" %}

```groovy

dependencyResolutionManagement {
		repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
		repositories {
			mavenCentral()
			maven { url 'https://jitpack.io' }
		}
	} 

```

{% endtab %}
{% endtabs %}

Step 2. Add the dependency

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
    dependencies {
        implementation ("com.github.tyrads-com:tyrads-sdk-android:LATEST_VERSION") // replace LATEST_VERSION with  1.1.0 or the latest stable version	}
```

{% endtab %}

{% tab title="Groovy" %}

```groovy
dependencies {
        implementation 'com.github.tyrads-com:tyrads-sdk-android:LATEST_VERSION'  // replace LATEST_VERSION with  1.1.0 or the latest stable version
	}1.1.0 or the latest stable version	}
```

{% endtab %}
{% endtabs %}


# Initialization

Integrating the Tyrads offerwall functionality into your application is a straightforward process that involves a few key steps. By following these integration steps, you can seamlessly incorporate the offerwall feature, enhancing user engagement and potentially generating revenue for your application.

### 1. Initialization

{% hint style="success" %}

### SDK Initialization best practices:

* **Initiate early:** It's advisable to initialize the SDK promptly after your app launches to ensure that all Tyr SDK functionalities are accessible when needed.
* **Initiate post-app authentication:** Re-initiate the SDK with current user details immediately after your user signs up or signs in to the app to update the `userId`.
* **Initiate periodically:** To optimize user experience, we strongly suggest invoking this method each time your app is brought to the forefront. This shouldn't impact your app's performance noticeably.
  {% endhint %}

This step initializes the Tyrads SDK within your application. You need to provide the API key and API secret obtained from the Tyrads platform. This allows your app to communicate securely with Tyrads' servers.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
CoroutineScope(Dispatchers.Main).launch {
    Tyrads.getInstance().init(
        context,
        apiKey: "xyz",
        apiSecret:"abc123",
        encryptionKey:"qwet",
        engagementId = 333",
        config = TyradsConfig(
            skipInitialPages = true
        ),
    );
}
```

{% endtab %}

{% tab title="Java" %}

<pre class="language-java"><code class="lang-java">Tyrads.getInstance().init(
<strong>    context,
</strong><strong>    "xyz",
</strong><strong>    "abc123",
</strong><strong>    engagementId = "333",
</strong>    config = TyradsConfig(
        skipInitialPages = true
    ),
<strong>    new TyradsCallback {
</strong>        override fun onSuccess() {
            Log.i("Tyrads", "Initialized successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to initialize: $error")
        }
    }
);
</code></pre>

{% endtab %}
{% endtabs %}

`encryptionKey`: This would be used for encrypting data transmitted from the SDK. If not provided, data will be transmitted plain form.

`engagementId`: (New) Optional engagement identifier to associate SDK activity with specific user engagements or campaigns.

`config`: (New) Configuration object (`TyradsConfig`) to customize SDK behavior. For example, `skipInitialPages` a Boolean (true or false) can be set dynamically. The `skipInitialPages` option in the `TyradsConfig` allows your app to bypass certain introductory pages during SDK initialization. When set to `true`, the SDK will **skip the Privacy and Terms & Conditions page as well as the Usage Permission page**, allowing users to enter directly into the main app experience without having to manually navigate through these consent or informational screens.

### 1.1 Advanced Practices for initialization for personalized rewards

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

To maximize the value of our Tyr SDK please follow the advanced options for initialization. This will allow us to personalize the rewards for the user event further and maximize the earnings for you as publisher.&#x20;

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
CoroutineScope(Dispatchers.Main).launch {
    val userInfo = TyradsUserInfo(
        email = "example@tyrads.com",
        phoneNumber = "0987653211223",
        userGroup = "High purchase user"
    )
    val mediaSourceInfo = TyradsMediaSourceInfo(
        mediaSourceName = "Facebook",
        mediaCampaignName = "Summer Sale",
        mediaSourceId = "123",
        mediaSubSourceId = "A1",
        incentivized = true,
        mediaAdsetName = "AdSet1",
        mediaAdsetId = "AS123",
        mediaCreativeName = "CreativeBanner",
        mediaCreativeId = "CB123",
        sub1 = "user123",
        sub2 = "app_launch",
        sub3 = "variantA",
        sub4 = "regionX",
        sub5 = "extraInfo"
    )
    Tyrads.getInstance().setMediaSourceInfo(mediaSourceInfo)
    Tyrads.getInstance().setUserInfo(userInfo)
    Tyrads.getInstance().init(
        context,
        apiKey: "xyz",
        apiSecret:"abc123",
        encryptionKey:"qwet",
        engagementId = 333",
        config = TyradsConfig(
            skipInitialPages = true
        ),
    );
}
```

{% endtab %}

{% tab title="Java" %}

<pre class="language-java"><code class="lang-java">TyradsUserInfo userInfo = new TyradsUserInfo(
    email = "example@tyrads.com",
    phoneNumber = "0987653211223",
    userGroup = "High purchase user"
);
TyradsMediaSourceInfo mediaSource = new TyradsMediaSourceInfo(
    mediaSourceName = "Facebook",
    mediaCampaignName = "Summer Sale",
    mediaSourceId = "123",
    mediaSubSourceId = "A1",
    incentivized = true,
    mediaAdsetName = "AdSet1",
    mediaAdsetId = "AS123",
    mediaCreativeName = "CreativeBanner",
    mediaCreativeId = "CB123",
    sub1 = "user123",
    sub2 = "app_launch",
    sub3 = "variantA",
    sub4 = "regionX",
    sub5 = "extraInfo"
);
Tyrads.getInstance().setMediaSourceInfo(mediaSource);
Tyrads.getInstance().setUserInfo(userInfo);
<strong>Tyrads.getInstance().init(
</strong>    context,
    "xyz",
    "abc123",
    engagementId = "333",
    config = TyradsConfig(
        skipInitialPages = true
    ),
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Initialized successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to initialize: $error")
        }
    }
);
</code></pre>

);
{% endtab %}
{% endtabs %}

* Always call `setMediaSourceInfo`  or `setUserInfo` immediately prior (before) to SDK `loginUser` or just after `init` to ensure all campaign metadata is tracked from session start.
* If certain fields in the `TyradsMediaSourceInfo`  or `TyradsUserInfo` class are not needed, simply omit them from your object creation—these fields will remain `null` by default and can be ignored unless explicitly set. There is no need to assign `null` manually; unassigned parameters will default automatically.

[Sending Media Source Data](/v3.0/getting-started/advanced-options/sending-media-source-data)

[Sending User Segments / User Info](/v3.0/getting-started/advanced-options/sending-user-segments-user-info)

### 2. User Login

Upon initializing the SDK, the mandatory step is to log in the user. However, passing a user ID is optional and is only necessary when the publisher operates its own user system. This login process ensures that user interactions with the offerwall are accurately tracked and attributed within the application.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
CoroutineScope(Dispatchers.Main).launch {
    Tyrads.getInstance().loginUser(
        userID: "xxx"
    );//userID is optional
} 
```

{% endtab %}

{% tab title="Java" %}

```java
Tyrads.getInstance().loginUser(
    "xxx",
    new TyradsLoginCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Login successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to login: $error")
        }
    }
); // userID is optional
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
The generated user ID from the SDK is based on the device identifier (GAID/OAID/IDFA)

* If your app user resets the device identifier, your user will lose the progress data
* If the SDK can't access the device identifier, it will generate its own device identifier and store it in the app storage. If this is the case, your app user will lose the progress data when the user uninstalls the app
* **If you send us your userId within userId field from your backened we will save this and even if the user changes their device ID we will ke ep their progress.**&#x20;
  {% endhint %}

### 3. Show Offerwall&#x20;

Once the SDK is initialized and the user is logged in (if applicable), you can display the offerwall to the user. This typically involves calling a function provided by the Tyrads SDK, such as showOffers. The offerwall is where users can engage with various offers, advertisements, or promotions provided by Tyrads, potentially earning rewards or incentives in the process.

{% tabs %}
{% tab title="Kotlin" %}

<pre class="language-kotlin"><code class="lang-kotlin">CoroutineScope(Dispatchers.Main).launch {
<strong>    Tyrads.getInstance().showOffers();
</strong><strong>}
</strong></code></pre>

{% endtab %}

{% tab title="Java" %}

```java
Tyrads.getInstance().showOffers(
    null,
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);
```

{% endtab %}
{% endtabs %}


# Deeplinking Routes

**NOTE**: **Min SDK version required: v1.1.8**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active offers` - opens the Activated Campaigns Page
* offers/\[id]- opens the Campaign Details Page (requires campaignID)
* `support` - opens the Campaign Tickets Page (requires campaignID)

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.getInstance().showOffers();

// Explicitly specifying the Campaigns Page
Tyrads.getInstance().showOffers(route: "offers");

// Activated Campaigns Page
Tyrads.getInstance().showOffers(route: "active-offers");

// Campaign Details Page (requires campaignID)
Tyrads.getInstance().showOffers(route: "offer", campaignID: "your_campaign_id_here");

// Campaign Tickets Page (requires campaignID)
Tyrads.getInstance().showOffers(route: "support", campaignID: "your_campaign_id_here");
```

{% endtab %}

{% tab title="Java" %}

```java
// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.getInstance().showOffers(
    null,
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Explicitly specifying the Campaigns Page
Tyrads.getInstance().showOffers(
    route: "offers",
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Activated Campaigns Page
Tyrads.getInstance().showOffers(
    route: "active-offers",
    null,
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Campaign Details Page (requires campaignID)
Tyrads.getInstance().showOffers(
    route: "offer",
    campaignID: "your_campaign_id_here",
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);

// Campaign Tickets Page (requires campaignID)
Tyrads.getInstance().showOffers(
    route: "support",
    campaignID: "your_campaign_id_here",
    new TyradsCallback {
        override fun onSuccess() {
            Log.i("Tyrads", "Offers displayed successfully")
        }

        override fun onFailure(error: String) {
            Log.e("Tyrads", "Failed to display offers: $error")
        }
    }
);
```

{% endtab %}
{% endtabs %}


# Premium Offers

### TopPremiumOffers Composable Function

#### Overview

The `TopPremiumOffers` composable function is designed to display top premium offers within the application. It utilizes the `TopOffers` composable to render the offers with specific settings.

#### Parameters:

* The `context` parameter is required and should be the context of the widget that will display the top offers widget.
* The `widgetStyle` parameter is used to choose the style of the widget. The default style is `PremiumWidgetStyles.LIST`, which displays the offers in a list. Other available style is `PremiumWidgetStyles.SLIDER_CARDS`, which displays the offers in a slider.

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

Return Value:

* `Widget`: A Composable `Widget` that can be embedded in your application's UI.

#### Usage

To use this composable, you can call it through the `Tyrads` instance like this:

```kotlin
Tyrads.getInstance().TopPremiumOffers(
    widgetStyle = Tyrads.PremiumWidgetStyles.SLIDER_CARDS
)
```

Or, use the default values:

```kotlin
Tyrads.getInstance().TopPremiumOffers()
```


# changeLanguage

This asynchronous method allows you to change the language used by the Tyrads SDK. It updates the SDK's internal locale settings.

```dart
Tyrads.getInstance().changeLanguage("en");
```

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.
* `supported Languages`: English (en), Spanish (es), Indonesian (id), Japanese (ja), Korean (ko) and Chinese (China, Simplified) (zh-Hans-CN)

#### Usage Example:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
Button(
  onClick = {
    CoroutineScope(Dispatchers.Main).launch {
      Tyrads.getInstance().changeLanguage('es'); // Change to Spanish
    }
  }
) {
  Text(text = "Change Language")
},
```

{% endtab %}

{% tab title="Java" %}

```java
private Button button;

button.setOnClickListener(
    v -> Tyrads.getInstance().changeLanguage(
            "id",
            new TyradsCallback {
                override fun onSuccess() {
                    Log.i("Tyrads", "Language changed successfully")
                }
        
                override fun onFailure(error: String) {
                    Log.e("Tyrads", "Failed to change language: $error")
                }
            }
        )
);
```

{% endtab %}
{% endtabs %}

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.


# Security & Device Integrity

To ensure the security of our services and protect against fraudulent activity, this SDK integrates the Google Play Integrity API for all Android requests.

#### Overview

The Play Integrity API helps protect your apps and games from potentially risky and fraudulent interactions. Our SDK automatically handles the generation and transmission of integrity tokens to ensure that the requests arriving at our servers originate from an unmodified version of your app running on a genuine Android device.

#### How it Works

The SDK follows a transparent, automated flow for every outgoing request:

1. Token Generation: For every network request, the SDK communicates with Google Play Services to obtain a unique, time-bound integrity token.
2. Header Injection: This token is automatically attached to the request header (e.g., `X-Play-Integrity`).
3. Server-Side Verification: Our backend receives the token and communicates with Google’s servers to verify the device's verdict (checking for rooted devices, emulators, or tampered app binaries).

#### Key Security Benefits

By using Google Play Integrity, we provide the following protections out of the box:

* Genuine App Binary: Ensures the request is coming from your official app, not a repackaged or modified version.
* Genuine Android Device: Detects if the app is running on a rooted device, an emulator, or a virtual framework that could be used for botting.
* Play Store Verdict: Verifies if the app was officially installed via Google Play.

#### Developer Requirements

No additional configuration is required on your part. The SDK handles the token lifecycle automatically.


# Obtaining Advertising ID's

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the AndroidManifest.xml file.

Navigate to the `android/app/src/main` directory inside your project's root, locate the AndroidManifest.xml file and add the following line just before the `<application>`.

```
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
```

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248)


# Prerequisite

* Android SDK 24 or higher using Google Play Services
* iOS version 11.0 or higher
* Flutter version 1.20.0 or higher
* Dart SDK version 2.12.0 or higher
* CocoaPods version 1.10.0 or higher


# Installation

Just open the terminal with project root working and type below command

```bash
flutter pub add tyrads_sdk
```

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FjxRWBSTcObUX1TCoTG61%2Fuploads%2F7Ijr9hVMl6oQnS9cob6i%2Fimage.png?alt=media&#x26;token=0f07cf11-6de6-4eb9-9039-052954e8bdf6" alt=""><figcaption></figcaption></figure>


# Initialization

Integrating the Tyrads offerwall functionality into your application is a straightforward process that involves a few key steps. By following these integration steps, you can seamlessly incorporate the offerwall feature, enhancing user engagement and potentially generating revenue for your application.

### 1. Initialization

{% hint style="success" %}

### SDK Initialization best practices:

* **Initiate early:** It's advisable to initialize the SDK promptly after your app launches to ensure that all Tyr SDK functionalities are accessible when needed.
* **Initiate post-app authentication:** Re-initiate the SDK with current user details immediately after your user signs up or signs in to the app to update the `userId`.
* **Initiate periodically:** To optimize user experience, we strongly suggest invoking this method each time your app is brought to the forefront. This shouldn't impact your app's performance noticeably.
  {% endhint %}

This step initializes the Tyrads SDK within your application. You need to provide the API key and API secret obtained from the Tyrads platform. This allows your app to communicate securely with Tyrads' servers.

```dart
Tyrads.instance.init( apiKey: "xyz", apiSecret:"abc123");
```

### 1.1 Advanced Practices for intialization for personalized rewards

{% hint style="warning" %}
To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users aswell as customize the earnings journey of different segments of users.&#x20;
{% endhint %}

To maximize the value of our Tyr SDK please follow the advanced options for intialization. This will allow us to personalize the rewards for the user event further and maximize the earnings for you as publisher.&#x20;

```
Tyrads.instance
      .init(
        apiKey: Env.TYRADS_SDK_KEY,
        apiSecret: Env.TYRADS_SDK_SECRET,
        encKey: Env.TYRADS_ENCYPTION_KEY,
        userInfo: TyradsUserInfo(
          email: "example@tyrads.com",
          phoneNumber: "001234567890",
          userGroup: "High purchase user",
        ),
        mediaSourceInfo: TyradsMediaSourceInfo(
          mediaSourceName: "Facebook",
          mediaCampaignName: "Summer2023Promo",
          mediaSourceId: "FB001",
          mediaSubSourceId: "FB001_Stories",
          incentivized: false,
          mediaAdsetName: "YoungAdults25-34",
          mediaAdsetId: "AD001",
          mediaCreativeName: "SummerSale_Video",
          mediaCreativeId: "CR001",
          sub1: "ReferralCode123",
          sub2: "OrganicInstall",
          sub3: "HighValueUser",
          sub4: "FirstTimeUser",
          sub5: "iOSDevice",
        ),
      );
```

[Sending Media Source Data](/v3.0/getting-started/advanced-options/sending-media-source-data)

[Sending User Segments / User Info](/v3.0/getting-started/advanced-options/sending-user-segments-user-info)

encKey: It stands for "encryption key" and would be used for encrypting data transmitted from the SDK. If not provided data will be transmitted in plain form.

### 2. User Login

Upon initializing the SDK, the mandatory step is to log in the user. However, passing a user ID is optional and is only necessary when the publisher operates its own user system. This login process ensures that user interactions with the offerwall are accurately tracked and attributed within the application.

```dart
await Tyrads.instance.loginUser(userID: "xxx");//userID is optional 
```

{% hint style="warning" %}
The generated user ID from the SDK is based on the device identifier (GAID/OAID/IDFA)

* If your app user resets the device identifier, your user will lose the progress data
* If the SDK can't access the device identifier, it will generate its own device identifier and store it in the app storage. If this is the case, your app user will lose the progress data when the user uninstalls the app
* **If you send us your userId within userId field from your backened we will save this and even if the user changes their device ID we will keep their progress.**&#x20;
  {% endhint %}

### 3. Show Offerwall

Once the SDK is initialized and the user is logged in (if applicable), you can display the offerwall to the user. This typically involves calling a function provided by the Tyrads SDK, such as showOffers, passing in the context of your application. The offerwall is where users can engage with various offers, advertisements, or promotions provided by Tyrads, potentially earning rewards or incentives in the process.

```dart
Tyrads.instance.showOffers(context);
```

<details>

<summary><strong>Launch Mode</strong></summary>

**Min SDK version required: v1.1.7**

**Works only for iOS**

Tyrads SDK provides the ability to open the Offerwall in a webkit view that is embedded in the app to provide a seamless user experience. Also, it provides the ability to open the Offerwall in an external browser (Safari) if Apple's app store policy does not approve the in-app rewards system for the app.

Available launch modes:

* `launchMode: 3` - opens the Offerwall in an external browser (Safari)
* `launchMode: 2` - opens the Offerwall in a webkit view that is embedded in the app

```js

// Note: The launchMode parameter is optional, if not specified the default would be opening the Offerwall in an external browser (Safari)

Tyrads.showOffers(context, launchMode: 3 );// provide launchMode: 2 to open the Offerwall in a webkit view that is embedded in the app
```

</details>

Usage example of `showOffers` with the `onClose` callback:

```dart
Tyrads.instance.showOffers(
  context,
  // Optional parameters you can uncomment and use:
  // campaignID: 00,
  // route: TyradsDeepRoutes.CAMPAIGN_TICKETS,
);
```

Explanation:<br>

* When the offerwall screen is closed, the `onClose` callback will be invoked.
* In this example, `Navigator.pop(context)` will close the current screen and return to the previous one in the navigation stack.

**Deeplinking Routes**

**Min SDK version required: v1.1.4**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `offers` - opens the Campaigns Page
* active-offers - opens the Activated Campaigns Page
* `offers/[id]` - opens the Campaign Details Page (requires campaignID)
* `support` - opens the Campaign Tickets Page (requires campaignID)

```dart
// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.instance.showOffers(context);

// Explicitly specifying the Campaigns Page
Tyrads.instance.showOffers(context, route: "offers");
//or use TyradsDeepRoutes class to avoid typos
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.OFFERS);

// Activated Campaigns Page
Tyrads.instance.showOffers(context, route: "active-offers");
// or using TyradsDeepRoutes class like
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.ACTIVE_OFFERS);

// Campaign Details Page (requires campaignID)
Tyrads.instance.showOffers(context, route: "offer", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.OFFER, campaignID: "your_campaign_id_here");

// Campaign Tickets Page (requires campaignID)
Tyrads.instance.showOffers(context, route: "support", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.SUPPORT, campaignID: "your_campaign_id_here");
```

### Premium Offers

This method returns a pre-built Flutter widget that displays a list of top offers. It provides several customization options to control the widget's appearance and behavior.

```dart
Tyrads.instance.topOffersWidget(
    context,
    widgetStyle: PremiumWidgetStyles.list
)
```

#### Parameters:

* The `context` parameter is required and should be the context of the widget that will display the top offers widget.
* The `widgetStyle` parameter is used to choose the style of the widget. The default style is `PremiumWidgetStyles.list`, which displays the offers in a list. Other available style is `PremiumWidgetStyles.sliderCards`, which displays the offers in a slider.

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

Return Value:

* `Widget`: A Flutter `Widget` (specifically, a `TopOffersWidget`) that can be embedded in your application's UI.

#### Usage Example:

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Offers')),
      body: Column(
        children: [
          Tyrads.instance.topOffersWidget(
            context,
            widgetStyle: PremiumWidgetStyles.list
          ),
          // ... other widgets
        ],
      ),
    );
  }
}
```

### `changeLanguage`

This asynchronous method allows you to change the language used by the Tyrads SDK. It updates the SDK's internal locale settings.

```dart
Tyrads.instance.changeLanguage("en");
```

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.
* `supported Languages`: English (en), Spanish (es), Indonesian (id), Japanese (ja), Korean (ko) and Chinese (China, Simplified) (zh-Hans-CN)

#### Usage Example:

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

ElevatedButton(
  onPressed: () {
    Tyrads.instance.changeLanguage('es'); // Change to Spanish
  },
  child: Text('Change to Spanish'),
),
```

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.


# Deeplinking Routes

**NOTE: Min SDK version required: v1.1.4**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active-offers` - opens the Activated Campaigns Page
* offers/\[id] - opens the Campaign Details Page (requires campaignID)
* `support` - opens the Campaign Tickets Page (requires campaignID)

```dart
// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.instance.showOffers(context);

// Explicitly specifying the Campaigns Page
Tyrads.instance.showOffers(context, route: "offers");
//or use TyradsDeepRoutes class to avoid typos
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.OFFERS);

// Activated Campaigns Page
Tyrads.instance.showOffers(context, route: "active-offers");
// or using TyradsDeepRoutes class like
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.ACTIVE_OFFERS);

// Campaign Details Page (requires campaignID)
Tyrads.instance.showOffers(context, route: "offer", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.OFFER, campaignID: "your_campaign_id_here");

// Campaign Tickets Page (requires campaignID)
Tyrads.instance.showOffers(context, route: "support", campaignID: "your_campaign_id_here");
// or using TyradsDeepRoutes class like
Tyrads.instance.showOffers(context, route: TyradsDeepRoutes.SUPPORT, campaignID: "your_campaign_id_here");
```


# Premium Offers

The **Premium Widget** is a UI element that becomes available after SDK initialization. It is independent of the SDK itself and can be dragged into any **Canvas** within your application.

\
The **Premium Widget** provides seamless access to various offerwall features:

* **More Offers** – Opens the full offerwall.
* **Active Offers** – Displays active offers.
* Campaing record - Open the page with campaign details. &#x20;
* **Play** – Redirects users to the store.

This method returns a pre-built Flutter widget that displays a list of top offers. It provides several customization options to control the widget's appearance and behavior.

```dart
Tyrads.instance.topOffersWidget(
  BuildContext context, {
    PremiumWidgetStyles widgetStyle = PremiumWidgetStyles.list,
  }
)
```

#### Parameters:

* The `context` parameter is required and should be the context of the widget that will display the top offers widget.
* The `widgetStyle` parameter is used to choose the style of the widget. The default style is `PremiumWidgetStyles.list`, which displays the offers in a list. Other available style is `PremiumWidgetStyles.sliderCards`, which displays the offers in a slider.

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

Return Value:

* `Widget`: A Flutter `Widget` (specifically, a `TopOffersWidget`) that can be embedded in your application's UI.

#### Usage Example:

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Offers')),
      body: Column(
        children: [
          Tyrads.instance.topOffersWidget(context),
          // ... other widgets
        ],
      ),
    );
  }
}
```


# changeLanguage

This asynchronous method allows you to change the language used by the Tyrads SDK. It updates the SDK's internal locale settings.

```dart
Tyrads.instance.changeLanguage("en");
```

#### Parameters:

* `languageCode` (String): A string representing the desired language code (e.g., "en" for English, "es" for Spanish, "fr" for French). This should be a valid ISO 639-1 language code.
* `supported Languages`: English (en), Spanish (es), Indonesian (id), Japanese (ja), Korean (ko) and Chinese (China, Simplified) (zh-Hans-CN)

#### Usage Example:

```dart
import 'package:tyrads_sdk/tyrads_sdk.dart';

ElevatedButton(
  onPressed: () {
    Tyrads.instance.changeLanguage('es'); // Change to Spanish
  },
  child: Text('Change to Spanish'),
),
```

#### Notes:

* This method persists the selected language in shared preferences so that it persists between app sessions.
* Make sure your application and the Tyrads SDK support the language code you are passing, otherwise english will be set.
* This method is asynchronous because it involves writing to shared preferences.
* Consider providing a language selection UI in your application that allows users to choose their preferred language if not Sdk itself provides user to select prefered language.


# Security & Device Integrity

To ensure the security of our services and protect against fraudulent activity, this SDK integrates the Google Play Integrity API for all Android requests.

#### Overview

The Play Integrity API helps protect your apps and games from potentially risky and fraudulent interactions. Our SDK automatically handles the generation and transmission of integrity tokens to ensure that the requests arriving at our servers originate from an unmodified version of your app running on a genuine Android device.

#### How it Works

The SDK follows a transparent, automated flow for every outgoing request:

1. Token Generation: For every network request, the SDK communicates with Google Play Services to obtain a unique, time-bound integrity token.
2. Header Injection: This token is automatically attached to the request header (e.g., `X-Play-Integrity`).
3. Server-Side Verification: Our backend receives the token and communicates with Google’s servers to verify the device's verdict (checking for rooted devices, emulators, or tampered app binaries).

#### Key Security Benefits

By using Google Play Integrity, we provide the following protections out of the box:

* Genuine App Binary: Ensures the request is coming from your official app, not a repackaged or modified version.
* Genuine Android Device: Detects if the app is running on a rooted device, an emulator, or a virtual framework that could be used for botting.
* Play Store Verdict: Verifies if the app was officially installed via Google Play.

#### Developer Requirements

No additional configuration is required on your part. The SDK handles the token lifecycle automatically.


# Obtaining Advertising ID's

**Android 12**

Apps updating their target API level to 31 (Android 12) or higher will need to declare a Google Play services normal permission in the AndroidManifest.xml file.

Navigate to the `android/app/src/main` directory inside your project's root, locate the AndroidManifest.xml file and add the following line just before the `<application>`.

Copy

<pre><code><strong>&#x3C;uses-permission android:name="com.google.android.gms.permission.AD_ID" />
</strong></code></pre>

You can read more about Google Advertising ID changes [here](https://support.google.com/googleplay/android-developer/answer/6048248).

**iOS 14+**

You need to add `NSUserTrackingUsageDescription` to `Info.plist` file like

```
<key>NSUserTrackingUsageDescription</key>
<string>We use device identification to personalize your rewards experience, track your progress, and provide tailored offers. This helps us improve our services and ensure you get the most value from our rewards program.</string>
```

Request IDFA Permission&#x20;

Tyrads SDK can work with or without the IDFA permission on iOS 14+. If no permission is granted in the ATT popup, the SDK will serve non personalized offers to the user. In that scenario the conversion is expected to be lower. Offerwall integrations perform better compared to when no IDFA permission is given. Our recommendation is that you should ask for IDFA usage permission prior to Tyrads sdk initialization.

```
<key>NSUserTrackingUsageDescription</key>
	<string>We use device identification to personalize your rewards experience, track your progress, and provide tailored offers. This helps us improve our services and ensure you get the most value from our rewards program.</string>

```


# Prerequisites

Before you begin, ensure you have met the following requirements:

* You have obtained your API key and API secret from the TyrAds.
* You have Node.js installed (version 18.0 or later recommended).
* For React Native projects, ensure you have React Native CLI installed and your development environment set up.


# Installation

To install the `@tyrads.com/tyrads-sdk` package, run the following command: `npm install @tyrads.com/tyrads-sdk`


# Initialization

To get started with the `@tyrads.com/tyrads-sdk` package, you will need to:

1. &#x20;Request an API key and API secret from the TyrAds team.
2. Initialize the SDK by calling `Tyrads.init()` and passing in your&#x20;
   1. API key&#x20;
   2. API secret&#x20;
   3. encKey: It stands for "encryption key" and would be used for encrypting data transmitted from the SDK. If not provided, data will be transmitted plain form.
   4. engagementId: \**Optional*\* Unique identifier for tracking user engagement.
   5. mediaSource: To maximize the value to the user sending us more data about the user and where they came from allow us to customize the reward experience. This can be used to provide feedback of quality of users as well as customize the earnings journey of different segments of users.&#x20;
   6. userInfo:  Data on user information.

```js
import Tyrads, { type TyradsMediaSourceInfo, type TyradsUserInfo } from '@tyrads.com/tyrads-sdk';

const mediaSource: TyradsMediaSourceInfo = {
  mediaSourceName: "ExampleSource",
  mediaCampaignName: "Spring Campaign",
  mediaSourceId: "src123",
  mediaSubSourceId: "subSrc456",
  incentivized: true,
  mediaAdsetName: "AdSet A",
  mediaAdsetId: "adset789",
  mediaCreativeName: "Creative X",
  mediaCreativeId: "creative101",
  sub1: "value1",
  sub2: "value2",
  sub3: "value3",
  sub4: "value4",
  sub5: "value5",
};

const userInfo: TyradsUserInfo = {
  email: "demo@example.com",
  phoneNumber: "+1234567890",
  userGroup: "premium_users",
}

await Tyrads.init(
  "apiKey",
  "apiSecret",
  "encKey",
  "engagementId",
  mediaSource,
  userInfo,
);

```

3. Login the user by calling `Tyrads.loginUser()` and passing in the user's ID.
4. Call `Tyrads.showOffers()` to display the offers.

**Launch Mode**

**Min SDK version required: v1.1.6**

**Works only for iOS**

Tyrads SDK provides the ability to open the Offerwall in a webkit view that is embedded in the app to provide a seamless user experience. Also, it provides the ability to open the Offerwall in an external browser (Safari) if Apple's app store policy does not approve the in-app rewards system for the app.

Available launch modes:

* `launchMode: 3` - opens the Offerwall in an external browser (Safari)
* `launchMode: 2` - opens the Offerwall in a webkit view that is embedded in the app

```js

// Note: The launchMode parameter is optional, if not specified the default would be opening the Offerwall in an external browser (Safari)

Tyrads.showOffers({ launchMode: 3 });// provide launchMode: 2 to open the Offerwall in a webkit view that is embedded in the app

```


# Deeplinking Routes

**Min SDK version required: v1.1.4**

The Tyrads SDK supports deeplinking to specific sections of the offerwall. When initializing or interacting with the SDK, you can specify a route to open a particular page. For campaign-specific routes, you'll need to provide the campaignID as well.

Available routes and their usage:

* `offers` - opens the Campaigns Page
* `active-offers` - opens the Activated Campaigns Page
* offers/\[id] - opens the Campaign Details Page (requires campaignID)
* `support` - opens the Campaign Tickets Page (requires campaignID)

```javascript

// Note: CAMPAIGNS is the default route when no specific route is provided
Tyrads.showOffers();

// Explicitly specifying the Campaigns Page
Tyrads.showOffers({route: "offers"});

// Activated Campaigns Page
Tyrads.showOffers({route: "active-offers"});

// Campaign Details Page (requires campaignID)
Tyrads.showOffers({route: "offer", campaignID: "your_campaign_id_here"});

// Campaign Tickets Page (requires campaignID)
Tyrads.showOffers({route: "support", campaignID: "your_campaign_id_here"});


```

**Basic Usage**

Here is an example of how to use the `@tyrads.com/tyrads-sdk` package:

```javascript
import  Tyrads  from  '@tyrads.com/tyrads-sdk';
const  TYR_SDK_API_KEY  =  'YOUR_API_KEY';
const  TYR_SDK_API_SECRET  =  'YOUR_API_SECRET';
const  initializeTyrSDK  = async () => {
  await Tyrads.init(TYR_SDK_API_KEY, TYR_SDK_API_SECRET);
  await Tyrads.loginUser(userId);
};

const  initializeAndShowOffers  = async () => {
 await initializeTyrSDK();
 await Tyrads.showOffers();
};
```


# Premium Offers

## `topPremiumOffers`

The `topPremiumOffers` component is a part of the `Tyrads` SDK that provides a UI widget to display premium offers. It allows for extensive customization to control what type of offers are shown and how they are presented.

### Usage

```jsx
import Tyrads from '@tyrads.com/tyrads-sdk';

function OffersScreen() {
  return (
    <SafeAreaView style={{ flex: 1 }}>
      {Tyrads.topPremiumOffers({
        viewStyle: TyradsPremiumWidgets.list,
      })}
    </SafeAreaView>
  );
}
```

#### Parameters:

* The `context` parameter is required and should be the context of the widget that will display the top offers widget.
* The `widgetStyle` parameter is used to choose the style of the widget. The default style is `PremiumWidgetStyles.list`, which displays the offers in a list. Other available style is `PremiumWidgetStyles.sliderCards`, which displays the offers in a slider.

**Available Widget Style options**

<figure><img src="/files/pmkTkVXEfP8BjgHKJ7SK" alt=""><figcaption><p>Option 1</p></figcaption></figure>

<figure><img src="/files/zMADmZXKS3LZtzT4sJkN" alt=""><figcaption><p>Option 2 </p></figcaption></figure>

Return Value:

* Component: A `React Component` (specifically, a `TopOffers`) that can be embedded in your application's UI.

***

### Example with Customization

```jsx
import Tyrads from '@tyrads.com/tyrads-sdk';

function CustomOffersScreen() {
  return (
    <SafeAreaView style={{ flex: 1 }}>
      {Tyrads.topPremiumOffers({
        viewStyle: PremiumWidgetStyle.list,
      })}
    </SafeAreaView>
  );
}
```

### Notes

* Ensure that `Tyrads.init()` and `Tyrads.loginUser()` are called before rendering `topPremiumOffers` to ensure the necessary data is available.
* The `viewStyle` property directly affects the visual presentation; experiment with different values to find the most suitable layout for your app.




---

[Next Page](/llms-full.txt/1)

