S2S ping: Difference between revisions

From Wiki Kaminari Click
No edit summary
(Marked this version for translation)
Line 1: Line 1:
<languages/>
<languages/>
<translate>
<translate>
<!--T:1-->
= General workflow =
= General workflow =
# The user arrives at your website. You generate a unique <code>kmnrId</code> and send it to Kaminari server via /ping URL, and we save the data in the cache.
# The user arrives at your website. You generate a unique <code>kmnrId</code> and send it to Kaminari server via /ping URL, and we save the data in the cache.
Line 10: Line 11:
## We also periodically check the cache and look for expired clicks that came to /ping but remained unpaired. If we couldn't verify them in any way, we write them to statistics with the status "Technical Losses."
## We also periodically check the cache and look for expired clicks that came to /ping but remained unpaired. If we couldn't verify them in any way, we write them to statistics with the status "Technical Losses."


= Client-side configuration =
= Client-side configuration = <!--T:2-->


<!--T:3-->
== Sending data to https://kaminari.systems/v2/ping ==
== Sending data to https://kaminari.systems/v2/ping ==
When a user visits the page, it is necessary to generate a unique display <code>kmnrId</code> on the client-side backend.
When a user visits the page, it is necessary to generate a unique display <code>kmnrId</code> on the client-side backend.


<!--T:4-->
Then, using PHP, Python, NodeJS, depending on the technology your website is built on, send initializing information to the https://kaminari.systems/v2/ping in the background.
Then, using PHP, Python, NodeJS, depending on the technology your website is built on, send initializing information to the https://kaminari.systems/v2/ping in the background.


<!--T:5-->
The request may not be accepted on the first attempt (in which case, the server will respond with a 204 status),  so we recommend sending the request in a loop until you receive a response with a 200 status.
The request may not be accepted on the first attempt (in which case, the server will respond with a 204 status),  so we recommend sending the request in a loop until you receive a response with a 200 status.


<!--T:6-->
The data should be sent using the POST method in JSON format.
The data should be sent using the POST method in JSON format.


<!--T:7-->
List of parameters:
List of parameters:


<!--T:8-->
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 46: Line 53:
|}
|}


<!--T:9-->
In addition, the following headers obtained from the user should be added to this request:
In addition, the following headers obtained from the user should be added to this request:
{| class="wikitable"
{| class="wikitable"
Line 84: Line 92:
|}
|}


<!--T:10-->
Example in CURL:
Example in CURL:
<pre>
<pre>
Line 99: Line 108:
</pre>
</pre>


<!--T:11-->
Example in PHP:
Example in PHP:
<pre>
<pre>
Line 115: Line 125:
]);
]);


<!--T:12-->
curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
curl_setopt( $ch, CURLOPT_HTTPHEADER, [
curl_setopt( $ch, CURLOPT_HTTPHEADER, [
Line 126: Line 137:
</pre>
</pre>


<!--T:13-->
== Adding kmnrId to the script ==
== Adding kmnrId to the script ==
The generated <code>kmnrId</code>, as well as the <code>kmnrKey</code> and sub-tags, should then be passed into the call of the JavaScript script on the page.
The generated <code>kmnrId</code>, as well as the <code>kmnrKey</code> and sub-tags, should then be passed into the call of the JavaScript script on the page.


<!--T:14-->
<pre>
<pre>
<script>
<script>
Line 143: Line 156:
     };
     };


     var kmnrSc = document.createElement('script');
     <!--T:15-->
var kmnrSc = document.createElement('script');
     var kmnrPrnt = document.getElementsByTagName('head')[0] || document.body;
     var kmnrPrnt = document.getElementsByTagName('head')[0] || document.body;
     kmnrSc.setAttribute('async', true);
     kmnrSc.setAttribute('async', true);
Line 152: Line 166:
</pre>
</pre>


= Testing =
= Testing = <!--T:16-->


<!--T:17-->
For testing data transmission and ensuring their compatibility with the API, you can use the following URL: https://kaminari.systems/v1/pingtest
For testing data transmission and ensuring their compatibility with the API, you can use the following URL: https://kaminari.systems/v1/pingtest


<!--T:18-->
=== Example in PHP: ===
=== Example in PHP: ===
<pre>
<pre>
Line 173: Line 189:
     ]);
     ]);


     curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
     <!--T:19-->
curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
     curl_setopt( $ch, CURLOPT_HTTPHEADER, [
     curl_setopt( $ch, CURLOPT_HTTPHEADER, [
         'Content-Type:application/json',
         'Content-Type:application/json',
Line 193: Line 210:
     echo "&lt;pre&gt;2. Response body: $body&lt;/pre&gt;";
     echo "&lt;pre&gt;2. Response body: $body&lt;/pre&gt;";


     'curl error: ' . curl_error($ch);
     <!--T:20-->
'curl error: ' . curl_error($ch);
     curl_close($ch);
     curl_close($ch);
} catch (Exception $e) {
} catch (Exception $e) {
Line 200: Line 218:
</pre>
</pre>


<!--T:21-->
Response :
Response :
<pre>
<pre>
Line 217: Line 236:
</pre>
</pre>


<!--T:22-->
=== Example in Node.js: ===
=== Example in Node.js: ===
<pre>
<pre>
const https = require('https');
const https = require('https');


<!--T:23-->
const payload = JSON.stringify({
const payload = JSON.stringify({
     'kmnrKey': 'XXXXXXXX',
     'kmnrKey': 'XXXXXXXX',
Line 233: Line 254:
});
});


<!--T:24-->
const options = {
const options = {
     host: 'kaminari.click',
     host: 'kaminari.click',
Line 248: Line 270:
};
};


<!--T:25-->
const req = https
const req = https
     .request(options, (res) => {
     .request(options, (res) => {
         let data = '';
         let data = '';


         res.on('data', (chunk) => {
         <!--T:26-->
res.on('data', (chunk) => {
             data += chunk;
             data += chunk;
         });
         });
Line 266: Line 290:
     });
     });


<!--T:27-->
req.on('error', (err) => {
req.on('error', (err) => {
     console.log("Error: " + err.message);
     console.log("Error: " + err.message);
Line 273: Line 298:
</pre>
</pre>


<!--T:28-->
Response:
Response:
<pre>
<pre>

Revision as of 02:11, 19 September 2023

Other languages:

General workflow

  1. The user arrives at your website. You generate a unique kmnrId and send it to Kaminari server via /ping URL, and we save the data in the cache.
  2. Then you show the user a page with our JavaScript script, adding the same kmnrId to the script call.
  3. We collect user data and send it to the server.
  4. On the server, we check in the cache:
    1. If there is a record with a similar kmnrId (coming from /ping), we combine the data from the cache with the results of the check and write them to the statistics.
    2. If there is no record with such an kmnrId, we wait up to five minutes. If the second record still does not arrive, we write what we have in the statistics.
    3. We also periodically check the cache and look for expired clicks that came to /ping but remained unpaired. If we couldn't verify them in any way, we write them to statistics with the status "Technical Losses."

Client-side configuration

Sending data to https://kaminari.systems/v2/ping

When a user visits the page, it is necessary to generate a unique display kmnrId on the client-side backend.

Then, using PHP, Python, NodeJS, depending on the technology your website is built on, send initializing information to the https://kaminari.systems/v2/ping in the background.

The request may not be accepted on the first attempt (in which case, the server will respond with a 204 status), so we recommend sending the request in a loop until you receive a response with a 200 status.

The data should be sent using the POST method in JSON format.

List of parameters:

Parameter Name Parameter Description Mandatory?
kmnrId Random impression identifier. Generated on the client side. It can be anything - UUID, random number, random string of text. Must be sent as a string. yes
kmnrKey Integration identifier within which the impression is analyzed. yes
sub1 Filled sub-tags. If you do not use certain tags, there is no need to send them. no
sub2 ... нет
sub3 ... нет
sub4 ... нет
sub5 ... нет
sub6 ... нет
sub7 ... нет

In addition, the following headers obtained from the user should be added to this request:

Parameter Name Parameter Description
user-agent User agent
referer Page the user came from
accept-language Browser interface language
x-original-ip Real user IP
x-forwarded-for IP
x-real-ip IP
sec-ch-ua-arch
sec-ch-ua
sec-ch-ua-full-version
device-memory
dpr
sec-ch-ua-mobile
sec-ch-ua-model
sec-ch-ua-platform
sec-ch-ua-platform-version
viewport-width

Example in CURL:

curl 'https://kaminari.systems/v2/ping' \
  -H 'accept: application/json' \ 
  -H 'accept-language: en-US,en;q=0.9' \ 
  -H 'cache-control: no-cache' \ 
  -H 'content-type: text/plain;charset=UTF-8' \
  -H 'origin: https://test.com' \ 
  -H 'pragma: no-cache' \ 
  -H 'referer: https://test.com/' \ 
  -H 'user-agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' 
  --data-raw '{"kmnrKey":"XXXXXXXX","kmnrId":"1125570260","sub1":"test","sub2":"1001","sub3":"10","sub4":"1385282124113622","sub5":"222","sub6":"555666","sub7":"8833705265931305"}' 
  --compressed

Example in PHP:

$url = 'https://kaminari.systems/v2/ping';
$ch = curl_init( $url );
$payload = json_encode([
    'kmnrKey' => 'XXXXXXXX',
    'kmnrId' => '1125570260',
    'sub1' => 'test',
    'sub2' => '1001',
    'sub3' => '10',
    'sub4' => '1385282124113622',
    'sub5' => '222',
    'sub6' => '555666',
    'sub7' => '8833705265931305',
]);

curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
curl_setopt( $ch, CURLOPT_HTTPHEADER, [
    'Content-Type:application/json',
    'Accept-Language:' . $_SERVER['HTTP_ACCEPT_LANGUAGE'],
    'User-Agent:' . $_SERVER['HTTP_USER_AGENT'],
    isset($_SERVER['HTTP_REFERER']) ? 'Referer:' . $_SERVER['HTTP_REFERER'] : '',
]);
curl_exec($ch);
curl_close($ch);

Adding kmnrId to the script

The generated kmnrId, as well as the kmnrKey and sub-tags, should then be passed into the call of the JavaScript script on the page.

<script>
    window.kmnr = {
        kmnrKey: 'XXXXXXXX',
        kmnrId: '1125570260',
        sub1: 'test',
        sub2: '1001',
        sub3: '10',
        sub4: '1385282124113622',
        sub5: '222',
        sub6: '555666',
        sub7: '8833705265931305',
    };

    var kmnrSc = document.createElement('script');
    var kmnrPrnt = document.getElementsByTagName('head')[0] || document.body;
    kmnrSc.setAttribute('async', true);
    kmnrSc.setAttribute('charset', 'utf-8');
    kmnrSc.src = '//kaminari.systems/v1/script.js?kmnrKey=' + window.kmnr.kmnrKey;
    kmnrPrnt && kmnrPrnt.appendChild(kmnrSc);
</script>

Testing

For testing data transmission and ensuring their compatibility with the API, you can use the following URL: https://kaminari.systems/v1/pingtest

Example in PHP:

$url = 'https://kaminari.systems/v1/pingtest';
try {
    $ch = curl_init( $url );
    $payload = json_encode([
        'kmnrKey' => 'XXXXXXXX',
        'kmnrId' => (string)mt_rand(),
        'sub1' => 'test',
        'sub2' => '1001',
        'sub3' => '10',
        'sub4' => '40',
        'sub5' => '555',
        'sub6' => '6',
        'sub7' => '77777',
    ]);

    curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
    curl_setopt( $ch, CURLOPT_HTTPHEADER, [
        'Content-Type:application/json',
        'Accept-Language:' . $_SERVER['HTTP_ACCEPT_LANGUAGE'],
        'User-Agent:' . $_SERVER['HTTP_USER_AGENT'],
        'DPR:2',
        isset($_SERVER['HTTP_REFERER']) ? 'Referer:' . $_SERVER['HTTP_REFERER'] : 'Referer:""',
    ]);
    curl_setopt( $ch, CURLOPT_HEADER, true);
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    
    $response = curl_exec($ch);
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, 0, $header_size);
    $body = substr($response, $header_size);
    $body = str_replace('", "', '",<br />    "', $body);
    $body = str_replace('{ "', '{<br />    "', $body);
    echo "<pre>1. Response length: $header_size</pre>";
    echo "<pre>2. Response body: $body</pre>";

    'curl error: ' . curl_error($ch);
    curl_close($ch);
} catch (Exception $e) {
    echo "Error register User: {$e->getMessage()}";
}

Response :

1. Response length: 287
2. Response body: {"errors": {
    "X-Forwarded-For":"recommended to add in request headers",
    "X-Real-IP":"recommended to add in request headers",
    "sec-ch-ua-arch":"recommended to add in request headers",
    "sec-ch-ua":"recommended to add in request headers",
    "sec-ch-ua-full-version":"recommended to add in request headers",
    "device-memory":"recommended to add in request headers",
    "sec-ch-ua-mobile":"recommended to add in request headers",
    "sec-ch-ua-model":"recommended to add in request headers",
    "sec-ch-ua-platform":"recommended to add in request headers",
    "sec-ch-ua-platform-version":"recommended to add in request headers",
    "viewport-width":"recommended to add in request headers"}}

Example in Node.js:

const https = require('https');

const payload = JSON.stringify({
    'kmnrKey': 'XXXXXXXX',
    'kmnrId': (Math.random() + 1).toString(36).substring(9),
    'sub1': 'test',
    'sub2': '1001',
    'sub3': '10',
    'sub4': '40',
    'sub5': '555',
    'sub6': '6',
    'sub7': '77777',
});

const options = {
    host: 'kaminari.click',
    port: 443,
    path: '/v1/pingtest',
    method: 'POST',
    headers: { 
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(payload),
        'Accept-Language': 'en-US,en;q=0.5',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0',
        'DPR': '2',
        'Referer': '""',
    }
};

const req = https
    .request(options, (res) => {
        let data = '';

        res.on('data', (chunk) => {
            data += chunk;
        });
        
        res.on('end', () => {
            try {
                data = JSON.parse(data);
                console.log(data);
            } catch {
                console.log(data);
            }
        });
    });

req.on('error', (err) => {
    console.log("Error: " + err.message);
});
req.write(payload);
req.end();

Response:

{
  errors: {
    'X-Forwarded-For': 'recommended to add in request headers',
    'X-Real-IP': 'recommended to add in request headers',
    'sec-ch-ua-arch': 'recommended to add in request headers',
    'sec-ch-ua': 'recommended to add in request headers',
    'sec-ch-ua-full-version': 'recommended to add in request headers',
    'device-memory': 'recommended to add in request headers',
    'sec-ch-ua-mobile': 'recommended to add in request headers',
    'sec-ch-ua-model': 'recommended to add in request headers',
    'sec-ch-ua-platform': 'recommended to add in request headers',
    'sec-ch-ua-platform-version': 'recommended to add in request headers',
    'viewport-width': 'recommended to add in request headers'
  }
}