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
Python
Node.js
PHP
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}'

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
Python
Node.js
PHP
curl 'https://proxykite.com/api/v1/proxies/7/traffic' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'

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
Python
Node.js
PHP
curl 'https://proxykite.com/api/v1/proxies/7/traffic/top?period=7d&limit=10' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'
{"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
Python
Node.js
PHP
curl 'https://proxykite.com/api/v1/proxies/7/traffic/recent?limit=50' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'
{"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
Python
Node.js
PHP
curl -X POST 'https://proxykite.com/api/v1/proxies/7/traffic/live-token' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'
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
Python
Node.js
PHP
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'

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
Python
Node.js
PHP
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'

Errors

StatuserrorMeaning
409insights_offtraffic insights are off for this proxy
409log_offno access log on the box
503node_offlinethe box has no tunnel to the cloud router
503agent_too_oldthe box runs an agent older than 1.5.0
503agent_timeoutthe box did not answer in time
503gateway_unavailablethe cloud router does not offer traffic insights yet or cannot be reached
429busytoo many requests for this box at once
403admin_reason_requiredsite admin without reason