Reporting APIs
Some of the analytics & reporting APIs support segmentation and date filtering. To apply them, use the following query parameters:
-
segment_id
- visit the Luigis Analytics Dashboard and switch to desired segmentation. Copy segmentation id from the current URL (a value of parameterapply_segment
). For example, for this URLhttps://app.luigisbox.com/sites/XXX-XXX/searches?apply_segment=999
, value ofsegment_id
is999
. -
from
- if given, only sessions starting after midnight of datefrom
will be taken into account. Required format:YYYY-MM-DD
(e.g.,2021-12-21
) -
to
- if given, only sessions starting before the end of dateto
will be taken into account. Required format:YYYY-MM-DD
(e.g.,2021-12-30
)
from
should be set to 2021-12-30
and to
should be set to 2021-12-30
, as well.
Breakdown
GET https://analytics.luigisbox.com/breakdown
The breakdown endpoint returns the high-level search KPIs, the same KPIs that you can see in the Luigi's Box dashboard funnel. All of the attributes in the response should be interpreted as percentages in the interval <0, 1>, e.g. 0.23
means 23%. In attributes sessions
and searches
you can find absolute numbers that are used to calculate these percentages.
Query Parameters
Parameter | Description |
---|---|
from |
ISO 8601 formatted start date of the interval in which the KPIs will be computed. |
to |
ISO 8601 formatted end date of the interval in which the KPIs will be computed. |
days |
Number of past days relative to the beginning of the current day to compute the KPIs from. E.g., setting days=0 will set from to the beginning of the current day and to to the end of the current day. Setting days=1 will set from to the beginning of yesterday and to to the end of the current day. Note that days parameter is mutually exclusive with the from and to parameter. |
Request Headers
Consider sending request header of Accept-Encoding
as well with values for supported encoding methods of your HTTP client, e.g. gzip
or br, gzip, deflate
for multiple supported methods. Encodings make the response from Breakdown endpoint considerably smaller and thus faster to transfer.
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/breakdown") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/breakdown", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/breakdown" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/breakdown"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/breakdown', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/breakdown", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/breakdown'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
{
"not_used_search_percent": 0.23,
"not_used_search_converted_percent": 0.20,
"not_used_search_not_converted_percent": 0.80,
"used_search_percent": 0.77,
"search_converted_percent": 0.21,
"search_not_converted_percent": 0.79,
"no_results_searches_percent": 0.05,
"no_click_searches_percent": 0.3,
"clicked_searches_percent": 0.65,
"sessions": {
"total_sessions": 1568,
"not_used_search_sessions": 360,
"not_used_search_converted_sessions": 72,
"not_used_search_not_converted_sessions": 288,
"used_search_sessions": 1207,
"search_converted_sessions": 253,
"search_not_converted_sessions": 953
},
"searches": {
"total_searches": 1500,
"no_results_searches": 75,
"no_click_searches": 450,
"clicked_searches": 975
}
}
Filters
GET https://analytics.luigisbox.com/filters?pair[]=categories:Laptops
Filters endpoint gives you information about filters used for searching. See the analytics documentation section on Filters for more information.
Filter is a pair of a name and a value. Both the name and value are taken from search analytics data.
When you invoke the endpoint without any parameters you will get an overview of all filters used, with basic statistical information - how many users used the filter and what was its conversion rate. The API returns the filter information in a hierarchy - filter name first, and then its values nested underneath. See the example on the right.
Filters are ordered by users_count
attribute on the first level, and then by the filter conversion rate on the values
level.
You can also pass an optional pair[]
parameter to get information about filters used in conjunction with the filter sent in pair[]
parameter. This can be understood as: "What other filters were used together with this filter?". For example, to answer the question: "What were the most used filters in "Laptops" category?", you can make a following request
The recommended way to use this API is to first invoke the endpoint without any parameters to get a list of all filter pairs. Each pair also contains a HATEOAS self
link with prepopulated pair[]
parameter. We recommend that you use this link, instead of trying to build it yourself.
Query Parameters
Parameter | Description |
---|---|
pair[] |
Filter pair in the name:value format to limit filter usage data to. Repeat this parameter multiple times to limit data to several filters at once. |
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/filters") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/filters", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/filters" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/filters"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/filters', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/filters", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/filters'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
[
{
"name": "Categories",
"users_count": 11793,
"conversion_rate": 2.74,
"values": [
{
"name": "Laptop",
"users_count": 644,
"conversion_rate": 8.58,
"links": [
{
"rel": "self",
"href": "https://analytics.luigisbox.com/filters?pair[]=Categories:Laptop"
}
]
},
{
"name": "Desktop",
"users_count": 1595,
"conversion_rate": 5.45,
"links": [
{
"rel": "self",
"href": "https://analytics.luigisbox.com/filters?pair[]=Categories:Desktop"
}
]
}
]
},
{
"name": "In Stock",
"users_count": 11793,
"conversion_rate": 2.74,
"values": [
{
"name": "Yes",
"users_count": 1192,
"conversion_rate": 4.41,
"links": [
{
"rel": "self",
"href": "https://analytics.luigisbox.com/filters?pair[]=In+Stock:Yes"
}
]
}
]
}
]
You can simply follow the self href
to get details on a specific filter pair.
Frequent queries
GET https://analytics.luigisbox.com/frequent_queries
The frequent queries endpoint gives you a list of your top queries, as we tracked them in Luigi's Box. All queries are lowercased and any non-ASCII characters are converted their ASCII approximation.
Request Headers
Consider sending request header of Accept-Encoding
as well with values for supported encoding methods of your HTTP client, e.g. gzip
or br, gzip, deflate
for multiple supported methods. Encodings make the response from Frequent queries endpoint considerably smaller and thus faster to transfer.
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/frequent_queries") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/frequent_queries", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/frequent_queries" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/frequent_queries"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/frequent_queries', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/frequent_queries", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/frequent_queries'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
[
{
"query": "query x",
"searches_count": 5917,
"links": [
{
"rel": "self",
"href": "https://analytics.luigisbox.com/query_detail?q=x"
}
]
},
{
"query": "query y",
"searches_count": 1475,
"links": [
{
"rel": "self",
"href": "https://analytics.luigisbox.com/query_detail?q=y"
}
]
},
{
"query": "query z",
"searches_count": 1127,
"links": [
{
"rel": "self",
"href": "https://analytics.luigisbox.com/query_detail?q=z"
}
]
}
]
You can simply follow the self href
to get details on a specific query.
No results queries
GET https://analytics.luigisbox.com/no_results_queries
The no results queries endpoint gives you a list of queries for which we tracked a "no-results" response in last 30 days. All queries are lowercased and any non-ASCII characters are converted their ASCII approximation.
Request Headers
Consider sending request header of Accept-Encoding
as well with values for supported encoding methods of your HTTP client, e.g. gzip
or br, gzip, deflate
for multiple supported methods. Encodings make the response from No results queries endpoint considerably smaller and thus faster to transfer.
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/no_results_queries") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/no_results_queries", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/no_results_queries" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/no_results_queries"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/no_results_queries', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/no_results_queries", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/no_results_queries'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
[
{
"query": "query x",
"searches_count": 5917,
"links": [
{
"rel": "self",
"href": "https://app.luigisbox.com/sites/23-7723/queries?in=Search+Results&q=query+x&show=noresults"
}
]
},
{
"query": "query y",
"searches_count": 1475,
"links": [
{
"rel": "self",
"href": "https://app.luigisbox.com/sites/23-7723/queries?in=Search+Results&q=query+y&show=noresults"
}
]
},
{
"query": "query z",
"searches_count": 1127,
"links": [
{
"rel": "self",
"href": "https://app.luigisbox.com/sites/23-7723/queries?in=Search+Results&q=query+z&show=noresults"
}
]
}
]
The
self href
leads to query detail page in Luigi's Box app.
Query Detail
GET https://analytics.luigisbox.com/query_detail?q=term
The query detail endpoint gives you top hits (in terms of CTR and conversions) of the chosen query.
Request Headers
Consider sending request header of Accept-Encoding
as well with values for supported encoding methods of your HTTP client, e.g. gzip
or br, gzip, deflate
for multiple supported methods. Encodings make the response from Query Detail endpoint considerably smaller and thus faster to transfer.
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/query_detail?q=term") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/query_detail", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/query_detail" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/query_detail?q=term"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/query_detail', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/query_detail?q=term", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/query_detail'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
{
"with_clicks": [
{
"title": "Product X",
"url": "www.e-shop.com/products/123",
"clicks": 465
},
{
"title": "Product Y",
"url": "www.e-shop.com/products/456",
"clicks": 324
}
],
"with_conversions": [
{
"title": "Product X",
"url": "www.e-shop.com/products/123",
"conversions": 29
},
{
"title": "Product Z",
"url": "www.e-shop.com/products/789",
"conversions": 16
}
]
}
Query Enhancement
GET https://live.luigisbox.com/rephrase?q=term
The query enhancement endpoint gives you a rephrased query for any given input query in order to avoid no or low converting search results.
Request Headers
Consider sending request header of Accept-Encoding
as well with values for supported encoding methods of your HTTP client, e.g. gzip
or br, gzip, deflate
for multiple supported methods. Encodings make the response from Query Enhancement endpoint considerably smaller and thus faster to transfer.
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/rephrase") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/rephrase", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/rephrase" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/rephrase"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/rephrase', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/rephrase", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/rephrase'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
{
"original_query": "term",
"rephrase_query": "other term"
}
Global ranking
GET https://analytics.luigisbox.com/ranking_global
The global ranking endpoint returns information about the optimal global ranking (ordering) of products. It returns a list of products identified by their canonical URLs and a numeric rank for each of the listed products. The rank is computed using Luigi's Box proprietary algorithms and considers many signals collected via search analytics. We recommend that you treat the rank as an opaque number on a strictly "lower is better" basis (as it is sorted). We also include "rev_rank" with reversed rank ("higher is better") for convenience.
The results returned by this API endpoint are paginated. To get to the next page, use the href
attribute in the links
section, where "rel": "next"
.
When you receive a response which contains no link with "rel": "next"
, it means that there are no more pages to scroll and you have downloaded the full ranking list.
- Output of the API is not sorted.
- The list of returned products is not exhaustive. We are explicitely ommiting products, for which no ranking information was collected.
- This API is not designed for real-time consumption. You should obtain the ranking data and cache it locally for fast access.
Request Headers
Consider sending request header of Accept-Encoding
as well with values for supported encoding methods of your HTTP client, e.g. gzip
or br, gzip, deflate
for multiple supported methods. Encodings make the response from Global ranking endpoint considerably smaller and thus faster to transfer.
Sample request
require 'faraday'
require 'faraday_middleware'
require 'json'
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
public_key = "<your-public-key>"
private_key = "<your-private-key>"
date = Time.now.httpdate
connection = Faraday.new(url: 'https://analytics.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/ranking_global") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "GET", "/ranking_global", date)}"
end
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
public_key="<your-public-key>"
private_key="<your-private-key>"
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
signature=$(digest "$private_key" "GET" "/ranking_global" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://analytics.luigisbox.com/ranking_global"
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
$public_key = "<your-public-key>";
$private_key = "<your-private-key>";
$signature = digest($private_key, 'GET', '/ranking_global', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://analytics.luigisbox.com/ranking_global", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
]);
echo $res->getStatusCode();
echo $res->getBody();
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Accept-Encoding: gzip, deflate
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - Date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var requestPath = '/ranking_global'
var timestamp = new Date().toUTCString();
var signature = ['GET', "application/json; charset=utf-8", timestamp, requestPath].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
// This endpoint requires no body
The above command returns JSON structured like this.
{
"total": 14256,
"ranks": [
{
"url": "https://eshop.com/products/123",
"rank": 1,
"rev_rank": 14257
},
{
"url": "https://eshop.com/products/456",
"rank": 2,
"rev_rank": 14256
},
{
"url": "https://eshop.com/products/918",
"rank": 3,
"rev_rank": 14255
}
],
"links": [
{
"rel": "next",
"href": "https://analytics.luigisbox.com/ranking_global?s=23937182663"
}
]
}