At a glance: Add signature validation to clicks to avoid fraud liabilities and so fraudulent clicks aren't attributed to your ad network.
About click signing
With minimal tech, fraudsters can send clicks on behalf of an ad network and create thousands, or even millions, of fake clicks that get sent to AppsFlyer. Sometimes, the ad networks themselves aren't aware of the issue.
In order for an ad network to ensure that clicks attributed to it by AppsFlyer actually originated from the ad network, and not from a fraudster creating fake clicks, ad networks should sign their clicks with HMAC-SHA256 signatures.
Click signing also prevents the ad network’s traffic from being blocked due to click flooding. Meaning, that if an ad network reaches the click-blocking threshold due to an extreme level of click flooding, AppsFlyer stops recording and attributing their clicks for the rest of the day.
The signatures enable AppsFlyer to validate the clicks and make sure that the click information hasn't been manipulated by fraudsters.
- Validated clicks are recorded, and attributed to the ad network
-
Invalidated clicks are rejected and:
- Are made available in Protect360 reports for ad networks (not advertisers). Learn more
- Do not impact the conversion rate or click-blocking threshold of the ad network
Click signature integration
Flow
The following chart outlines the flow from initial development and basic tests to production tests, and finally, to production.
Procedure
Prerequisite: API V2.0 token from the admin to authorize the click signing API.
To sign your clicks:
-
Generate a secret key with the Generate secret key API.
Best practice: Generate and use a new secret key every 24 hours, with an expiration of 36 hours. -
Develop code in your servers that calls the Generate secret key API, takes the secret key and generates an HMAC-SHA256 signature. See code sample.
You can use the other APIs as described in the table that follows. - The code adds the following to your click URLs:
- An expires parameter that contains a Unix timestamp (in UTC) after which the ad network doesn't claim the click.
- The HMAC-SHA256 signature.
Example:https://app.appsflyer.com/com.app.id?pid=adnetwork_int&c=my_campaign&clickid=sdkfjasksjskdfj9845weh&af_siteid=12345&expires=1597657118&signature_v2=8fnDVzZP_WRZnv3KNJaREOEfvB5p9oRc_XlKEvUo8gk
Note
Make sure any URL encoding of special characters or spaces in your link occurs before the click signature is generated. Generating the signature first results in verification failure.
Creating a click signature
To create a click signature you must:
- Build a JSON using the list of attributes and JSON rules below
- Create the signature from this JSON using HMAC56
List of attributes
The following list of attributes is supported for click and engagement signing.
Order | Parameter | Mandatory | Notes |
---|---|---|---|
1 | link_domain | Yes |
The domain from the click URL For example:
|
2 | link_path | Yes | The path of the click URL not including a leading backslash. app-id for single platform links or template-id for OneLink |
3 | pid | Yes | |
4 | af_prt | No | |
5 | af_siteid | Yes | |
6 | clickid | Yes | A one-time unique identifier of the click |
7 | expires | Yes | click expiration |
8 | af_engagement_type | No | |
9 | af_click_lookback | No | |
10 | af_viewthrough_lookback | No | |
11 | af_reengagement_window | No | |
12 | is_retargeting | No | |
13 | af_ip | No | |
14 | advertising_id | No | |
15 | oaid | No | |
16 | fire_advertising_id | No | |
17 | idfa | No | |
18 | idfv | No |
Attribute and JSON rules
Order and appearance of attributes
- Supported parameters in the engagement URL with a value must be in the JSON
- Attributes must be listed in the JSON in the order listed in the table above
Empty attributes
- Attributes listed in the JSON cannot be empty values or contain only spaces
JSON Data structure
- The JSON data structure must be an array of attributes
- Each attribute will be in the format ["key", "value"]
Example:[["key-1","value-1"],["key-2","value-2"]...["key-n","value-n"]]
- Each attribute will be in the format ["key", "value"]
Attribute value escaping
- The values in the JSON must be written in lowercase strings as defined in the JSON standard.
JSON spaces
- The JSON must be compacted. It should not contain any blanks, tabs, or newline characters between the values.
Signature algorithm
- Use HmacSHA256 with the secret key to create the signature for the JSON
- Encode the signature with Base64 without padding
- Add the signature to the click URL with a parameter signature_v2
//generate a signature from the click url and encode it with base64 without padding String generatedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(mac.doFinal(jsonString.getBytes()));
Signature example
Building a signature example
Example OneLink (multi-platform) click URL:
https://yourbrand.onelink.me/qsWL?pid=mediasource_int&advertising_id=12345678-1234-1234-1234-123456789012
&af_ad_type=video&af_adset=MMP&clickid=sdkfjasksjskdfj9845weh&af_siteid=my_site&af_viewthrough_lookback=2h&c=my_campaign
&expires=1689695615
Example json object for signature (before removing blank spaces):
[
["link_domain","yourbrand.onelink.me"],
["link_path","qswl"],
["pid","mediasource_int"],
["af_siteid","my_site"],
["clickid","12345"],
["expires","1689695615"]
]
Example json object for signature (after removing blank spaces)
[["link_domain","yourbrand.onelink.me"],["link_path","qswl"],["pid","mediasource_int"],["template-id","qswl"],["af_siteid","my_site"],["clickid","12345"],["expires","1689695615"]]
Final click URL with the signature:
https://yourbrand.onelink.me/qsWL?pid=mediasource_int&advertising_id=12345678-1234-1234-1234-123456789012
&af_ad_type=video&af_adset=MMP&af_siteid=my_site&af_viewthrough_lookback=2h&c=my_campaign
&expires=1689695615
&signature_v2=WIfCmfLAPSsVrBTqCqfihMeLCnbE4dIAlhHF84WsiWA
Code examples
signing-supported-params.json
[
{"index":1, "name":"pid", "mandatory":true},
{"index":2, "name":"af_prt", "mandatory":false},
{"index":3, "name":"af_siteid", "mandatory":true},
{"index":4, "name":"clickid", "mandatory":true},
{"index":5, "name":"expires", "mandatory":true},
{"index":6, "name":"af_engagement_type", "mandatory":false},
{"index":7, "name":"af_click_lookback", "mandatory":false},
{"index":8, "name":"af_viewthrough_lookback", "mandatory":false},
{"index":9, "name":"af_reengagement_window", "mandatory":false},
{"index":10, "name":"is_retargeting", "mandatory":false},
{"index":11, "name":"af_ip", "mandatory":false},
{"index":12, "name":"advertising_id", "mandatory":false},
{"index":13, "name":"oaid", "mandatory":false},
{"index":14, "name":"fire_advertising_id", "mandatory":false},
{"index":15, "name":"idfa", "mandatory":false},
{"index":16, "name":"idfv", "mandatory":false}
]
signature-example.go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"os"
"strings"
"time"
)
type Param struct {
Name string
Mandatory bool
}
func LoadSupportedParams() ([]Param, error) {
path := "./signing-supported-params.json"
jsonFile, _ := os.Open(path)
defer jsonFile.Close()
byteValue, err := io.ReadAll(jsonFile)
if err != nil {
return nil, errors.New("failed loading " + path)
}
var params []Param
_ = json.Unmarshal(byteValue, ¶ms)
return params, nil
}
func computeHmac256(message, secret string) (res string, errResult error) {
defer func() {
if r := recover(); r != nil {
errResult = r.(error)
fmt.Println("failed to invoke ComputeHmac256. err: %+v", errResult)
res = ""
return
}
}()
key := []byte(secret)
h := hmac.New(sha256.New, key)
h.Write([]byte(message))
return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(h.Sum(nil)), nil
}
// this function accepts a click url, a ttl for the click in seconds, and the list of supported params
// the function:
// 1. adds the expiration to the click based on the provided ttl
// 2. builds a json for the signature
// 3. create an HMAC256 signature
// 4. adds the signature to the click url
func signURLV2(originalURL string, secret string, clickTtlSeconds int64, supportedParams []Param) (signedURL string, err error) {
//add an expiration to the click
expires := time.Now().UTC().Unix() + clickTtlSeconds
urlWithExpired := fmt.Sprintf("%s%s%d", originalURL, "&expires=", expires)
//parse the url
parsedURL, err := url.Parse(urlWithExpired)
if err != nil {
return "", errors.New("failed parsing URL")
}
//build a json from the url
jsonStr, err := buildJSONFromURLV2(parsedURL, supportedParams)
if err != nil {
return "", err
}
//create a signature
signatureV2, err := computeHmac256(jsonStr, secret)
if err != nil {
fmt.Println("Failed to computeHMAC256 for url %s. err: %+v", jsonStr, err)
return "", errors.New("fail to computeHMAC256 for url")
}
//add the signature to the url
signedURL = fmt.Sprintf("%s%s%s", urlWithExpired, "&signature_v2=", signatureV2)
return signedURL, nil
}
// this function builds a json from a given click url.
// It returns a string representation of the json ready to be signed.
func buildJSONFromURLV2(parsedURL *url.URL, supportedParams []Param) (string, error) {
//initiate an empty json in the structure [[key-1,val-1],[key-2,val-2]...[key-n,val-n]]
var jsonData [][2]string
//add the url host domain to the json
domain := parsedURL.Host
param := [2]string{"link_domain", domain}
jsonData = append(jsonData, param)
//add the path (app-id or template-id) to the json
path := parsedURL.Path
if len(path) > 1 {
param := [2]string{"link_path", path[1:]}
jsonData = append(jsonData, param)
}
//loop over the ordered list of supported parameters and add them to the json
for i := 0; i <len(supportedParams); i++ {name := supportedParams[i].Name val := parsedURL.Query().Get(name) if len(val) > 0 {
param := [2]string{name, val}
jsonData = append(jsonData, param)
} else if supportedParams[i].Mandatory {
return "", errors.New("missing mandatory param: " + name)
}
}
//generate string representation of the json object
jsonObj, _ := json.Marshal(jsonData)
return strings.ToLower(string(jsonObj)), nil
}
func main() {
supportedParams, err := LoadSupportedParams()
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
}
var secretKey = "tqJU4Qd/eFTEWfqW7KCG9asDO0bmZoFzv8GY3VPSPAM="
var clickTtlSeconds int64 = 60
var originalUrl = "https://yourbrand.onelink.me/qsWL?pid=mediasource_int&advertising_id=12345678-1234-1234-1234-123456789012&clickid=1234&af_ad_type=video&af_adset=MMP&af_siteid=my_site&af_viewthrough_lookback=2h&c=my_campaign"
fmt.Println("Original URL: ", originalUrl)
signedUrl, err := signURLV2(originalUrl, secretKey, clickTtlSeconds, supportedParams)
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
} else {
fmt.Println("Signed URL: ", signedUrl)
}
}
Click signature APIs
AppsFlyer provides APIs that allow ad networks to manage and test the click signing process. See the list of APIs in the table below, and the sections that follow with information necessary for using the API.
Click signature APIs
API method | Remarks |
---|---|
Generate secret key | Generate secret keys to be used in the signature. |
Revoke secret key | Cancel compromised secret keys. |
Test | Send single clicks for testing the signature. |
Configure mode |
Configure mode of click signing mode:
|
Configure circuit breaker |
Configure the mode of the circuit breaker that protects the ad network from having too many blocked clicks:
|
Get configuration |
Get the mode and IDs of active secret keys. |
Report |
Get statistics on successful and failing clicks when the system is in report-only or enabled mode. Use this to test click signing without impacting production and real traffic. |
Exclude app | Configure app IDs to be excluded from click signing. |
Remove excluded app | Configure app IDs to be included in click signing after being excluded. |
Legacy versions
These versions should not be used and are listed for reference only
V1 - Legacy
Generate secret key method
Generate secret key basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | POST |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=<ttlHours> |
|
Authorization header |
|
|
Response | Results | Secret key returns in a JSON |
Request limit | Maximum of 2 active secret keys at a time |
API request
Method
POST https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=<ttlHours>
Parameters
Parameter |
Description |
---|---|
ttlHours |
|
JSON response
Key |
Description |
---|---|
secret-key-id |
An ID for the secret key |
secret key |
The secret key for the click signature |
expiration |
Epoch time in milliseconds |
Generate secret key curl example and response
Curl request
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=36' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
JSON response
{
"secret-key-id": "59ad6547-affc-45eb-a6c9-9805f88ee755",
"secret-key": "zGW6Rhrmb8+vuhHtL/Kp6rW5Ci9PNsjH1J5MGO9SIeg=",
"expiration": 1610533263
}
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Revoke secret key method
Revoke secrete key basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | DELETE |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/secret/<secret-id> |
|
Authorization header |
|
|
Response | Results | Empty |
API request
Method
DELETE https://hq1.appsflyer.com/api/p360-click-signing/secret/<secret-id>
Parameters
Parameter |
Description |
---|---|
secret-id |
The ID of the secret key to be revoked |
Generate secret key curl example and response
Curl request
curl --location --request DELETE 'https://hq1.appsflyer.com/api/p360-click-signing/secret/59ad6547-affc-45eb-a6c9-9805f88ee755' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Test method
Test basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | POST |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/test |
|
Authorization header |
|
|
Response | Results | Returns in a JSON |
API request
Method
POST https://hq1.appsflyer.com/api/p360-click-signing/test
Parameters
Parameter |
Description |
---|---|
url |
The click URL (including signature) to test |
JSON response
Key |
Description |
---|---|
test-status |
Either Passed or Failed |
message |
Reason for the test failure. For example:
|
Test curl example and response
Curl request
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/test' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}' \
--header 'Content-Type: application/json' \
--data-raw '{
"url": "https://app.appsflyer.com/com.app.id?pid=adnetwork_int&c=my_campaign&clickid=sdkfjasksjskdfj9845weh&af_site_id=12345&expires=1597657118&signature=8fnDVzZP_WRZnv3KNJaREOEfvB5p9oRc_XlKEvUo8gk"
}'
JSON response
{
"test-status":"Passed / Failed",
"message": "Invalid signature"
}
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Configure mode method
Configure mode basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | POST |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/config/mode/<mode> |
|
Authorization header |
|
|
Response | Results | Returns in a JSON |
API request
Method
POST https://hq1.appsflyer.com/api/p360-click-signing/config/mode/<mode>
Parameters
Parameter |
Description |
---|---|
mode |
Options:
|
Configure mode curl example
Curl request
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/config/mode/report-only' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
400 | Bad request |
Invalid mode |
401 | Not authorized |
Invalid or missing authorization header |
Configure circuit breaker method
Configure circuit breaker basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | POST |
Path |
https://hq1.appsflyer.com/p360-click-signing/config/circuit-breaker |
|
Authorization header |
|
|
Response | Results | HTTP status |
API request
Method
POST https://hq1.appsflyer.com/p360-click-signing/config/circuit-breaker
Request body JSON
Parameter |
Description |
---|---|
status |
|
Configure circuit breaker curl example and response
Curl request
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/config/circuit-breaker' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
--data-raw '{
"status":"enabled"
}'
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
400 | Bad request |
Invalid status |
401 | Not authorized |
Invalid or missing authorization header |
Get configuration method
Get configuration basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | GET |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/config |
|
Authorization header |
|
|
Response | Results | Returns in a JSON |
API request
Method
GET https://hq1.appsflyer.com/api/p360-click-signing/config
JSON response
Key |
Description |
---|---|
mode |
One of:
|
circuit-breaker-config |
A JSON object containing status, one of:
|
active-key-ids |
A JSON array holding active keys:
|
excluded-app-ids |
A JSON array with excluded app-ids |
Get configuration curl example and response
Curl request
curl --location --request GET 'https://hq1.appsflyer.com/api/p360-click-signing/config' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
JSON response
{
"mode": "report-only",
"active-key-ids": [
{
"secret-key-id": "59ad6547-affc-45eb-a6c9-9805f88ee755",
"expiration": 1610533263
}
],
"excluded-app-ids": [
"app-id-1", "app-id-2"
]
}
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Report method
Report basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | GET |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/report |
|
Authorization header |
|
|
Response | Results | Returns in a CSV |
API request
Method
GET https://hq1.appsflyer.com/api/p360-click-signing/report
Parameters
Parameter |
Description |
---|---|
start-date |
Start date and time for the report. Format: yyyy-mm-ddThh |
end-date |
End date and time for the report. Format: yyyy-mm-ddThh |
The API requires either both start-date and end-date or neither of them. If start/end date are not provided, the report shows results for the past 24 hours. |
CSV response
Column |
Description |
---|---|
time |
Date and time of the clicks. Format yyyy-mm-ddThh |
total_clicks |
Total number of clicks during the reporting period |
valid_clicks |
Number of valid clicks during the reporting period |
missing_signature |
Number of clicks missing signatures during the reporting period |
expired_clicks |
Number of expired clicks during the reporting period |
invalid_signature |
Number of clicks with invalid signatured during the reporting period |
no_active_secrets |
Number of clicks rejected because there are no active secret keys in the system (usually when the system is in report-only mode) |
Test curl example and response
Curl request
curl --location --request GET 'https://hq1.appsflyer.com/api/p360-click-signing/report?start-date=2021-01-07T07&end-date=2021-01-17T12' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}' \
CSV response
time |
total_clicks |
valid_clicks |
missing_signature |
expired_clicks |
invalid_signature |
no_active_signatures |
---|---|---|---|---|---|---|
2021-01-17T07 |
928082156 |
928082156 |
0 |
0 |
0 |
0 |
2021-01-17T08 |
923796132 |
923796132 |
0 |
0 |
0 |
0 |
2021-01-17T09 |
917541373 |
917541373 |
0 |
0 |
0 |
0 |
2021-01-17T10 |
909977064 |
909977064 |
0 |
0 |
0 |
0 |
2021-01-17T11 |
965104299 |
965104299 |
0 |
0 |
0 |
0 |
2021-01-17T12 |
975134824 |
975134824 |
0 |
0 |
0 |
0 |
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Exclude app method
Exclude app method basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | POST |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id> |
|
Authorization header |
|
|
Response | Results | Empty |
API request
Method
POST https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id>
Parameters
Parameter |
Description |
---|---|
app-id |
Application ID to be excluded from click signing validation |
Exclude app curl example
Curl request
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/appname.com' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Remove excluded app method
Remove excluded app method basics
Category | Item |
Description |
---|---|---|
Request | HTTP method | DELETE |
Path |
https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id> |
|
Authorization header |
|
|
Response | Results | Empty |
API request
Method
DELETE https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id>
Parameters
Parameter |
Description |
---|---|
app-id |
Application ID to be removed from the list of apps excluded from click signing validation |
Remove excluded app curl example
Curl request
curl --location --request DELETE 'https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/appname.com' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTP response codes
Response codes
Code |
Message |
Remarks |
---|---|---|
200 | OK |
|
401 | Not authorized |
Invalid or missing authorization header |
Code sample
package sign;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
.
.
.
String clickUrl = "https://app.appsflyer.com/com.app.id?pid=adnetwork_int&c=my_campaign&clickid=sdkfjasksjskdfj9845weh&af_site_id=12345";
String secretKey = "secret_key";
int ttlMinutes = 5;
//add expiration to the click URL
long expiration = System.currentTimeMillis() + (60000L * ttlMinutes);
clickUrl += "&expires="+expiration;
//create a SecretKey object from the given key string
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
//generate a signature from the click url and encode it with base64 without padding
String generatedSignature =
Base64.getUrlEncoder().withoutPadding().encodeToString(mac.doFinal(clickUrl.getBytes()));
//add the signature to the click URL
String signedClickUrl = clickUrl + "&signature=" + generatedSignature;
Additional information
Troubleshooting
AppsFlyer stops click signature validation and reverts to the report-only mode when more than 90% of clicks in an hour fail signature validation.
This is to protect your business from a potential technical issue and allows you to find the cause of the anomaly:
- If you find that the signature is working as expected and the clicks are being correctly blocked, disable the circuit-breaker using the configure circuit breaker method.
-
If you find that clicks are being incorrectly blocked:
- Make sure that you have a valid secret key by checking the click signing configuration using the get configuration method.
- Use the click signing report to get more information about the blocked clicks and investigate the sources (agency/app- iDs) and reasons for invalid clicks.
- If you find a problem with a specific app because of a non-standard integration, exclude this app from click signing validation using the exclude app API.
-
If you find a problem with your configuration:
- Continue running in report-only mode.
- Fix the click signing process on your side.
- Check the results in the click signing report and re-enable click-signing validation when you see that clicks are being validated as expected.
FAQ
Q: How can we test click signing without impacting production? A: There are two ways to test click signing:
|
Q: What is the difference between an API token and a secret-key? A: API token: Is used to authorize and run the click signing API. There is only one per ad network. The AppsFlyer API V2.0 token must be obtained from the admin Secret key: Is used to generate the signature. Use the generate secret key method to create secret keys. The ad network is responsible for generating new secret keys. See the traits section for more information. |
Q: Can we apply click signing to only certain campaigns? A: No. Click signing is applied to all clicks from an ad network. You can exclude certain apps from click signing, but you can’t exclude only certain campaigns. |
Traits
Trait |
Description |
---|---|
Click signature | The signature must occur on the ad network servers. |
Secret key |
|
Report API | Updated statistics of click validity are aggregated on an hourly basis. |