Traffic insights
See which websites a proxy connects to — live, as top domains per hour / day / week / month, and optionally in an
access log kept on your own box for the number of days you choose (1–90).
- Off by default. Only the account owner can switch it on (in the panel this asks for your password and shows the
notice below). Team admins can change the settings and look at the data; team viewers and reseller sub-users only see
that insights are on (
traffic.notice).
- What is recorded: domain name, port, time, data amounts, the login and the client IP that used the proxy. Never
page paths, query strings, headers, contents or passwords. HTTPS is never decrypted: for HTTPS connections made to a bare
IP the agent reads the site name the client sends in the TLS handshake (SNI, can be switched off with
traffic_sni).
- Where it is stored: the detailed log stays on your box (
/var/lib/hostyourproxy/traffic/, compressed, one file per
day, deleted after traffic_retention_days). The panel keeps only hourly per-domain totals (top 200 domains per hour).
- Needs agent 1.5.0 or newer on the box (
traffic.supported) and a cloud router that offers it.
Notice shown when switching on
ProxyKite will record which websites this proxy connects to (domain names, times, data amounts, the client IP that used
it). You are responsible for telling the people who use this proxy and for complying with the law where you and they are.
Logs are stored on your own machine for the days you choose.
Every proxy object carries the state:
"traffic": {"view": true, "log": true, "retention_days": 30, "sni": true, "supported": true,
"enabled_at": "2026-10-10T12:00:00+00:00",
"status": {"log_bytes": 1048576, "log_days": 3, "log_oldest": "2026-10-08", "log_pruned_early": false, "error": null},
"notice": "Traffic insights are on for this proxy"}
Site admins looking at another account's proxy must pass reason (5–500 characters) on every data call; it is
written to the audit log.
Switch on, change settings, switch off
PATCH /proxies/{id}
Ability: manage. Fields (any subset, may come alone): traffic_view, traffic_log (needs traffic_view),
traffic_retention_days (1–90), traffic_sni. Switching off (traffic_view: false) also stops the log; files already on
the box are deleted when they pass the retention days.
curl -X PATCH 'https://proxykite.com/api/v1/proxies/7' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"traffic_view":true,"traffic_log":true,"traffic_retention_days":30}'
import os
import requests
r = requests.patch(
"https://proxykite.com/api/v1/proxies/7",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
json={"traffic_view": True, "traffic_log": True, "traffic_retention_days": 30},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch('https://proxykite.com/api/v1/proxies/7', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({"traffic_view":true,"traffic_log":true,"traffic_retention_days":30}),
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{"traffic_view":true,"traffic_log":true,"traffic_retention_days":30}',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));
Errors: 409 agent_too_old (the box's agent is older than 1.5.0), 409 insights_off (traffic_log without traffic_view),
403 for team admins switching it on.
State
GET /proxies/{id}/traffic
Ability: read — everyone who sees the proxy. Returns the traffic object above.
curl 'https://proxykite.com/api/v1/proxies/7/traffic' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'
import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/proxies/7/traffic",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch('https://proxykite.com/api/v1/proxies/7/traffic', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7/traffic');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));
Top domains
GET /proxies/{id}/traffic/top?period=24h&limit=50
Ability: read. period = 1h, 24h (default), 7d, 30d; limit ≤ 200. From the hourly totals the box sends
once an hour has finished; everything outside the top domains is in other.
curl 'https://proxykite.com/api/v1/proxies/7/traffic/top?period=7d&limit=10' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'
import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/proxies/7/traffic/top?period=7d&limit=10",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch('https://proxykite.com/api/v1/proxies/7/traffic/top?period=7d&limit=10', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7/traffic/top?period=7d&limit=10');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));
{"data": {"period": "7d", "from": "2026-10-03T13:00:00+00:00",
"domains": [{"domain": "google.com", "conns": 1200, "bytes_in": 52428800, "bytes_out": 1024000, "denied": 0}],
"other": {"domain": "(other)", "conns": 31, "bytes_in": 1200, "bytes_out": 300, "denied": 1},
"total": {"conns": 1231, "bytes_in": 52430000, "bytes_out": 1024300, "denied": 1}}}
Recent connections
GET /proxies/{id}/traffic/recent?limit=100&since_seq=0
Ability: read. Read live from the box (the last 512 connections it remembers). Pass the seq of the previous answer
as since_seq to get only newer records — a simple way to poll.
curl 'https://proxykite.com/api/v1/proxies/7/traffic/recent?limit=50' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'
import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/proxies/7/traffic/recent?limit=50",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch('https://proxykite.com/api/v1/proxies/7/traffic/recent?limit=50', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7/traffic/recent?limit=50');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));
{"data": {"seq": 9813, "active": 3, "hour": "2026-10-10T12:00:00Z", "view": true, "log": true,
"records": [{"seq": 9813, "cid": 5522, "ts": 1760097601000, "te": 1760097601900, "u": "u7a", "cip": "198.51.100.9",
"p": "connect", "h": "www.google.com", "d": "google.com", "port": 443, "ip": "142.250.1.1", "sni": false,
"in": 5120, "out": 800, "r": "ok"}],
"top_now": [{"d": "google.com", "c": 120, "in": 5242880, "out": 102400, "denied": 0}]}}
Record fields: ts/te start/end (unix ms), u login ("" = whitelisted IP), cip client IP, p http | connect |
socks, h host, d registrable domain, port, ip the address dialled, sni (host read from TLS SNI), in/out bytes,
r result: ok, denied_private, denied_port, blocked_list (website rules), dial_error, dns_error, timeout.
Live stream
POST /proxies/{id}/traffic/live-token
Ability: read. Returns a one-minute, single-use URL on the cloud router that streams
Server-Sent Events:
curl -X POST 'https://proxykite.com/api/v1/proxies/7/traffic/live-token' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'
import os
import requests
r = requests.post(
"https://proxykite.com/api/v1/proxies/7/traffic/live-token",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch('https://proxykite.com/api/v1/proxies/7/traffic/live-token', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7/traffic/live-token');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));
const { data } = await (await fetch('/api/v1/proxies/7/traffic/live-token', { method: 'POST', headers })).json();
const es = new EventSource(data.url);
es.addEventListener('conn', (e) => console.log(JSON.parse(e.data))); // a connection ended (record)
es.addEventListener('open', (e) => console.log(JSON.parse(e.data))); // a connection started
es.addEventListener('tick', (e) => console.log(JSON.parse(e.data))); // {"active": n} every 5 s
es.addEventListener('end', () => es.close()); // ask for a new token to continue
es.onerror = () => es.close(); // the token works once: never auto-reconnect
Events: hello, open, conn, tick, end ({"reason": "max_age" | "insights_off" | "node_offline" | …}). A session
lasts at most 30 minutes; at most 4 viewers per proxy.
Access log
GET /proxies/{id}/traffic/logs?from=&to=&q=&user=&client_ip=&cursor=&limit=200
Ability: read. Searches the log files on the box (the box must be online), newest first. from/to: unix seconds or
an ISO date / date-time (UTC; default the last 24 h, at most 31 days). q = host contains, limit ≤ 1000. When cursor
is not null, pass it to get the next page; truncated: true means the box stopped after 5 seconds.
curl 'https://proxykite.com/api/v1/proxies/7/traffic/logs?from=2026-10-09&to=2026-10-10&q=google' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'
import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/proxies/7/traffic/logs?from=2026-10-09&to=2026-10-10&q=google",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch('https://proxykite.com/api/v1/proxies/7/traffic/logs?from=2026-10-09&to=2026-10-10&q=google', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7/traffic/logs?from=2026-10-09&to=2026-10-10&q=google');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));
Export the access log (CSV)
GET /proxies/{id}/traffic/logs/export?from=&to=
Ability: read. Answers 302 to a one-minute download URL on the cloud router (follow redirects). At most 31 days.
Columns: start_utc,end_utc,user,client_ip,proto,host,domain,port,ip,sni,bytes_in,bytes_out,result. Every export is in the
audit log.
curl 'https://proxykite.com/api/v1/proxies/7/traffic/logs/export?from=2026-10-01&to=2026-10-08' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: text/plain'
import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/proxies/7/traffic/logs/export?from=2026-10-01&to=2026-10-08",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code)
print(r.text)
const res = await fetch('https://proxykite.com/api/v1/proxies/7/traffic/logs/export?from=2026-10-01&to=2026-10-08', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.text());
<?php
$ch = curl_init('https://proxykite.com/api/v1/proxies/7/traffic/logs/export?from=2026-10-01&to=2026-10-08');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $status, PHP_EOL, $body;
Errors