Introduction ¶
Welcome to the Luigi's Box Live API! You can use our API to access Luigi's Box search analytics features.
We have examples in multiple languages. You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
Authentication ¶
Most of the available endpoints use HMAC authentication to restrict access. To use the API you'll need a
- public key — this is a
tracker_id
assigned to your site in Luigi's Box search analytics. You can see thetracker_id
in every URL in Luigi's Box application once you are logged in. - private key — you can find your private key in the API Keys section in Luigi's Box application.
If you need help contact our support.
Our API expects you to include these HTTP headers:
HTTP Header | Comment |
---|---|
Content-Type |
e.g., application/json; charset=utf-8 Standard HTTP header. Some endpoints allow you to POST JSON data, while some are purely GET-based |
Authorization |
e.g., ApiAuth 1292-9381:sd73hdh881gfop228 The general format is client tracker_id:digest . The client part is not used, it's best to provide your application name, or a generic name, such as "ApiAuth". You must compute the digest using the method described below. |
date |
e.g., Thu, 29 Jun 2017 12:11:16 GMT Request date in the HTTP format. Note that this is cross-validated on our servers and if your clock is very inaccurate, your requests will be rejected. We tolerate ±5 second inaccuracies. You will be including this timestamp in the digest computation, so what this means in plain terms is that you cannot cache the digest and must recompute it for each request. |
Content-Encoding optional |
e.g., gzip Optional HTTP header. Content updates endpoint allows you to use gzip or deflate request payload compression methods to send large payloads effectively. |
Digest computation ¶
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
date = Time.now.httpdate
digest("secret", "POST", "/v1/content", date)
<?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');
digest("secret", "POST", "/v1/content", $date);
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - 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 requestUri = request.url.replace(/^.\/\/[^\/]+/, '').replace(/\?.$/, '');
var timestamp = new Date().toUTCString();
var signature = [request.method, "application/json; charset=utf-8", timestamp, requestUri].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
postman.setGlobalVariable("authorization", "ApiAuth " + publicKey + ":" + encryptedSignature);
postman.setGlobalVariable("date", timestamp);
#!/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
}
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
echo $(digest "secret", "GET", "/v1/content", $date)
You must use HMAC SHA256 to compute the digest and it must be Base64 encoded.
Payload to be signed is computed as a newline-d concatenation of
- HTTP request method - e.g.,
GET
- Content-type header - e.g.,
application/json; charset=utf-8
- Date (in HTTP-date format) - the same value you are sending in
date
header - path (without query string) - e.g.
/filters
Make sure that you are using the same values for digest computation as for the
actual request. For example, if you compute digest from Content-Type:
application/json; charset=utf-8
, make sure you send the request with the exact same
Content-Type (and not e.g. Content-Type: application/json
).
Most programming languages provide crypto libraries which let you compute the HMAC digest with minimal effort. When the particular endpoint requires HMAC, we provide examples in several languages in the right column in its documentation.
The pseudocode for HMAC computation is:
signature = [request_method, content_type, timestamp, request_path].join("\n")
digest = base64encode(hmacsha256(signature, your_private_key))
Look for examples in the right column. You can find examples for other languages online, however, those were not tested by us. See the following external links for more examples:
Server will return HTTP 401 Not Authorized
if your authentication fails. If
this happens, look inside the response body. We include a diagnostics output
which will tell you what was wrong with your request.
Analytics APIs
Some of our analytics APIs support segmentation and date filtering. To apply them, use the following query parameters:
segment_id
- visit our 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
)
HTTP Request ¶
GET https://live.luigisbox.com/no_results_queries?segment_id=999&from=2021-01-01&to=2021-01-30
Breakdown ¶
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://live.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://live.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://live.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,
"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
}
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%.
HTTP Request ¶
GET https://live.luigisbox.com/breakdown
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.
Frequent queries ¶
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://live.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://live.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://live.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://live.luigisbox.com/query_detail?q=x"
}
]
},
{
"query": "query y",
"searches_count": 1475,
"links": [
{
"rel": "self",
"href": "https://live.luigisbox.com/query_detail?q=y"
}
]
},
{
"query": "query z",
"searches_count": 1127,
"links": [
{
"rel": "self",
"href": "https://live.luigisbox.com/query_detail?q=z"
}
]
}
]
You can simply follow the
self href
to get details on a specific query.
Our 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.
HTTP Request ¶
GET https://live.luigisbox.com/frequent_queries
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.
No results queries ¶
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://live.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://live.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://live.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.
Our 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.
HTTP Request ¶
GET https://live.luigisbox.com/no_results_queries
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.
Trending queries ¶
require 'faraday'
require 'faraday_middleware'
require 'json'
connection = Faraday.new(url: 'https://live.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/v2/trending_queries?tracker_id=1234-5678")
if response.success?
puts JSON.pretty_generate(JSON.parse(response.body))
else
puts "Error, HTTP status #{response.status}"
puts response.body
end
#!/bin/bash
curl -i -XGET --compressed\
"https://live.luigisbox.com/v2/trending_queries?tracker_id=1234-5678"\
<?php
// Using Guzzle (http://guzzle.readthedocs.io/en/latest/overview.html#installation)
require 'GuzzleHttp/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://live.luigisbox.com/v2/trending_queries?tracker_id=1234-5678", [
'headers' => [
'Accept-Encoding' => 'gzip'
]
]);
echo $res->getStatusCode();
echo $res->getBody();
// This endpoint requires no authentication
// This endpoint requires no body
The above command returns JSON structured like this.
[
{
"title": "Query A",
"links": [{
"rel": "top_content",
"href": "https://example.com/news/"
}]
},
{
"title": "query B"
}
]
Trending queries endpoint is particularly suited for building a "trending queries" widget on your site.
Calling this endpoint gives you a list of your top queries for the past 30 days but you can customize this list in the main Luigi's Box application. There are no API parameters, the output is only controlled from Luigi's Box application UI.
In the application, look for the menu "Trending queries API settings". If you don't see it, contact us to enable it.
From the management UI, you can:
- Set the number of returned queries
- Ban some queries from appearing in the API output
- Rewrite query text, e.g., to add accents or change caps
- Add your own queries, even if they are not trending at the moment
- Enable top hit loading for a query, you can use the top hit URL in the widget to send users directly to the most popular result for the query
HTTP Request ¶
GET https://live.luigisbox.com/v2/trending_queries
Query Parameters ¶
Parameter | Description |
---|---|
tracker_id | Identifier of your site within Luigi's Box. You can see this identifier in every URL in our app once you are logged-in. |
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 Trending queries endpoint considerably smaller and thus faster to transfer.
Query Detail ¶
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://live.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://live.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://live.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
}
]
}
The query detail endpoint gives you top hits (in terms of CTR and conversions) of the chosen query.
HTTP Request ¶
GET https://live.luigisbox.com/query_detail?q=term
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.
Converting items ¶
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://live.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/converting_items") 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", "/converting_items", 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" "/converting_items" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://live.luigisbox.com/converting_items"
<?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', '/converting_items', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://live.luigisbox.com/converting_items", [
'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 = '/converting_items'
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.
[
{
"item": "https://www.eshop.com/products/123",
"conversions_count": 25,
"converting_queries": [
{
"string": "foo",
"source": "Search Results",
"searches_count": 17,
"links": [
{
"rel": "self",
"href": "https://live.luigisbox.com/query_detail?q=foo"
}
]
},
{
"string": "bar",
"source": "Autocomplete",
"searches_count": 3,
"links": [
{
"rel": "self",
"href": "https://live.luigisbox.com/query_detail?q=bar"
}
]
}
]
}
]
The converting items endpoint gives you a list of your items, for which we recorded a search conversion in Luigi's Box. Each converting item has a list of queries from which the conversion happened.
- All queries are lowercased and any non-ASCII characters are converted to their ASCII approximation.
- The output is sorted by conversions. The first item is the one with most conversions.
- We are capping the number of converting items at 5000. Please contact us to request a limit increase.
- The output is computed in real-time, for each API call.
- This API when used in bulk (without
items
parameter) is not designed for real-time consumption. You should obtain the bulk data and cache it locally for fast access. - You may consume this API in real-time when scoping to a single item.
HTTP Request ¶
GET https://live.luigisbox.com/converting_items
You can also make a POST
request and include an array of items (their URLs) to scope the results to these items only.
POST https://live.luigisbox.com/converting_items
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 Converting items endpoint considerably smaller and thus faster to transfer.
To invoke POST request with results scoped to given items, use this code:
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://live.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.post("/converting_items") do |req|
req.headers['Content-Type'] = "application/json; charset=utf-8"
req.headers['Date'] = date
req.headers['Authorization'] = "faraday #{public_key}:#{digest(private_key, "POST", "/converting_items", date)}"
req.body = '[
"http://eshop.com/products/1",
"http://eshop.com/products/2"
]'
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" "POST" "/converting_items" "$date")
curl -i -XPOST --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://live.luigisbox.com/converting_items" -d '[
"http://eshop.com/products/1",
"http://eshop.com/products/2"
]'
<?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, 'POST', '/converting_items', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('POST', "https://live.luigisbox.com/converting_items", [
'headers' => [
'Accept-Encoding' => 'gzip, deflate',
'Content-Type' => 'application/json; charset=utf-8',
'Date' => $date,
'Authorization' => "guzzle {$public_key}:{$signature}",
],
'body' => '[
"http://eshop.com/products/1",
"http://eshop.com/products/2"
]'
]);
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 = '/converting_items'
var timestamp = new Date().toUTCString();
var signature = ['POST', "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);
// Example request body
[
"http://eshop.com/products/1",
"http://eshop.com/products/2"
]
Filters ¶
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://live.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://live.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://live.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://live.luigisbox.com/filters?pair[]=Categories:Laptop"
}
]
},
{
"name": "Desktop",
"users_count": 1595,
"conversion_rate": 5.45,
"links": [
{
"rel": "self",
"href": "https://live.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://live.luigisbox.com/filters?pair[]=In+Stock:Yes"
}
]
}
]
}
]
You can simply follow the
self href
to get details on a specific filter pair.
Filters endpoint gives you information about filters used for searching. See the Search analytics documentation section on Filters for more information.
Filter is always 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
GET https://live.luigisbox.com/filters?pair[]=categories:Laptops
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.
HTTP Request ¶
GET https://live.luigisbox.com/filters
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. |
Recommend items ¶
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://live.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/recommend_items?item_url=https://eshop.com/products/789") 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", "/recommend_items", 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" "/recommend_items" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://live.luigisbox.com/recommend_items?item_url=https://eshop.com/products/789"
<?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', '/recommend_items', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://live.luigisbox.com/recommend_items?item_url=https://eshop.com/products/789", [
'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 = '/recommend_items'
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.
[
{
"title": "a Title",
"url": "https://eshop.com/products/123"
},
{
"title": "another Title",
"url": "https://eshop.com/products/456"
}
]
The related items endpoint gives you a list of recommended items for a given item, identified by its URL.
HTTP Request ¶
GET https://live.luigisbox.com/recommend_items?item_url=https://eshop.com/products/789
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 Recommend items endpoint considerably smaller and thus faster to transfer.
Global ranking ¶
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://live.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://live.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://live.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://live.luigisbox.com/ranking_global?s=23937182663"
}
]
}
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.
HTTP Request ¶
GET https://live.luigisbox.com/ranking_global
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.
Per filter content ranking ¶
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://live.luigisbox.com') do |conn|
conn.use FaradayMiddleware::Gzip
end
response = connection.get("/ranking_per_filter?f=Category:Ladies+shirts") 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_per_filter", 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_per_filter" "$date")
curl -i -XGET --compressed\
-H "Date: $date" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: curl $public_key:$signature" \
"https://live.luigisbox.com/ranking_per_filter?f=Category:Ladies+shirts"
<?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_per_filter', $date);
$client = new GuzzleHttp\Client();
$res = $client->request('GET', "https://live.luigisbox.com/ranking_per_filter?f=Category:Ladies+shirts", [
'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_per_filter'
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.
[
"ranks": [
{
"url": "https://eshop.com/products/123",
"rank": 291.2
},
{
"url": "https://eshop.com/products/456",
"rank": 61.9
},
{
"url": "https://eshop.com/products/918",
"rank": 816.2
}
],
"links": [
{
"rel": "next",
"href": "https://live.luigisbox.com/ranking_global?f=Category:Ladies+shirts&s=23937182663"
}
]
]
The per filter ranking endpoint returns information about the optimal ranking of products with respect to a single filter, provided as a key:value pair. It returns a list of products identified by their canonical URLs and a numeric rank for each of the listed products with respect to the provided filter. 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 "higher is better" basis.
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.
- You cannot ask for ranking for arbitrary filter. The optimal ranking will be learned only for the agreed filter names (but for all of the filter values).
- 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.
HTTP Request ¶
GET https://live.luigisbox.com/ranking_per_filter?f=Category:Ladies+shirts
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 Per filter content ranking endpoint considerably smaller and thus faster to transfer.