Protect gross margin
Compare traffic by customer, package, and destination with the commercial plan to identify costly workloads and plans priced below their usage shape.
Analytics turns completed proxy activity into operational and commercial evidence. Use it to answer what consumed traffic, which destinations and targeting combinations were used, where failures occurred, and whether your local billing projection still matches the platform.
Eligible completed requests become historical records: who used data, how much, where and through which route.
Feed · overall traffic · domainsCurrent users, package access and working balances support authorization. Live connection counters answer what is active now.
ConnectionsWarnings and failures carry their own status, error and request context. They are not successful request rows.
LogsAccounting records are separate: orders and ledgers describe durable entitlements and usage. The optional transactions view is not a copy of the request feed.
Customer-facing dashboards and API operations expose usage, requests, destinations, active connections, and proxy errors. Operators can additionally inspect technical metrics, provider health, configured alerts, and incident history through deployment-level monitoring surfaces.
Distributed tracing is not provided. Correlate a customer report with request IDs, time windows, gateway context, analytics feed rows, and proxy error logs instead. Provider health and incident operations are operator-facing and should not be assumed to have the same public API coverage as customer analytics.
A historical request row is queued after successful completion, when analytics is enabled for the selected provider and the request has an authenticated user. The storage layer requires identity, client IP, destination and provider context. Writes are asynchronous and can fail: this is not a guarantee that every attempted request appears in the feed.
The current request record has 31 fields. The map below distinguishes what is stored from what the public GET /analytics/feed response exposes. “Not exposed” means absent from that public feed, not that the field is available through another customer endpoint.
| Stored field | Meaning | Public feed |
|---|---|---|
user_id | Account that authenticated the request. | user_id |
reseller_id | Reseller relationship attached to the request. | reseller_id |
package_id | Package used for access. | package_id |
package_slug | Package alias used by proxy authentication. | Not exposed |
ledger_id | Purchased data bucket charged for this traffic, when present. A shared-pool child can consume a parent ledger. | ledger_id |
username | Proxy authentication username, including any targeting tokens. | username |
| Stored field | Meaning | Public feed |
|---|---|---|
request_id | Identifier for this request or tunnel. | id |
data | Accounted traffic in bytes, not a monetary amount or request-body size. | data |
established_connections | Connection count captured with the record; not a live reading when you later query the feed. | established_connections |
timestamp | UTC time recorded on successful completion, at second precision. | timestamp |
date | UTC calendar date derived from that timestamp for storage organization. | Not exposed |
| Stored field | Meaning | Public feed |
|---|---|---|
user_ip | Client peer IP observed by the gateway. | user_ip |
server_ip | Proxy gateway server IP; not the destination-facing exit IP. | server_ip |
cluster | Gateway cluster identifier. | Not exposed |
hostname | Destination hostname. This row does not include URL paths, query strings, headers or bodies. | hostname |
protocol | Proxy protocol used for the request. | protocol |
method | Method or tunnel operation recorded by the proxy. | method |
| Stored field | Meaning | Public feed |
|---|---|---|
provider_id | Selected upstream provider identifier. | Not exposed |
provider | Selected upstream provider name. | Not exposed |
pool | Selected routing pool. | pool |
pool_country | Country from the selected pool configuration or eligible pool location. | Not exposed |
pool_region | Region from the selected pool configuration or eligible pool location. | Not exposed |
pool_city | City from the selected pool configuration or eligible pool location. | Not exposed |
| Stored field | Meaning | Public feed |
|---|---|---|
continent | Continent targeting attached to the request. | Not exposed |
country | Country targeting attached to the request. | country |
region | Region targeting attached to the request. | region |
city | City targeting attached to the request. | city |
asn | Requested autonomous system number; stored as 0 when absent. | asn |
| Stored field | Meaning | Public feed |
|---|---|---|
session_id | Sticky-session identifier. The public feed exposes presence only, not the identifier. | is_session (boolean) |
session_key | Internal sticky-session key. Restrict access and redact before exports or support tickets. | Not exposed |
password | Proxy authentication password. This is a credential, not a dashboard dimension; restrict access and redact it. | Not exposed |
Requested country, region, city, continent and asn describe targeting. The separate pool_* fields describe a configured or selected pool location. Neither is an independent measurement of the exit IP’s location. Use an IP-check service through the proxy if you need to verify the observed exit.
Missing routing or session context can be empty. An unset ASN is stored as 0. The feed converts session presence to is_session; it does not return a session key. It returns ASN as a result field but does not offer an ASN query filter.
This request row does not store HTTP bodies, headers, a full destination URL, or elapsed request time. Performance metrics and warning/error logs are separate sources; do not infer those fields from the historical feed.
The internal record can include the proxy password and session key. These are restricted credentials, not fields to display in a customer dashboard. They are absent from the public feed. Apply least-privilege access, retention controls and redaction to internal exports as well.
| Question | Endpoint | Returned view | Why it is useful |
|---|---|---|---|
| How many connections are active now? | GET /analytics/connections | User, package, server IP, connection count | Capacity dashboards, concurrency support, and detecting abandoned clients |
| How did traffic change over time? | GET /analytics/overall | Time buckets with bytes and request count | Usage charts, anomaly detection, customer summaries, and closed-window reconciliation |
| Which destinations consume the most? | GET /analytics/domains | Hostname, requests, and bytes | Cost concentration, customer behavior, allow/block policy reviews, and abuse investigation |
| What happened on an individual request? | GET /analytics/feed | Request-level identity, traffic, destination, protocol, pool, geo, ASN, and session data | Reproducing routing behavior and explaining a customer’s traffic record |
| Why did requests fail? | GET /analytics/logs | Status, proxy error code/message, identity, destination, geo, and timestamp | Support triage, provider incident correlation, and retry-policy tuning |
| Which recorded transactions are available? | GET /analytics/{id}/transactions | Sender, recipient, type, amount, package, details, and time | Investigating recorded movements when transactions are enabled; not a complete allocation, purchase or expiry journal |
overall is the primary chart and reconciliation surface. It fills missing buckets with zeroes and returns both data and requests. Short windows use hour-level buckets; longer windows use daily buckets. Always store the requested start, end, and IANA timezone next to your own report so the same commercial period can be reproduced.
Use feed when you need evidence at request granularity and domains when you need a ranked aggregate. Feed rows can distinguish customers, packages, and ledgers; show the destination and client/proxy IPs; and explain the protocol, method, pool, targeting, ASN, and sticky-session usage associated with the byte count.
Domain aggregation is better for questions such as “which destinations generated 70% of traffic?” without downloading every request row. Treat destination hostnames as potentially sensitive customer data.
connections is an operational snapshot rather than a historical traffic report. Compare its per-server counts with package concurrency limits to distinguish real capacity pressure from a historical usage spike.
logs reads proxy warning/error records, not successful requests. Filter it by protocol, error code, package, ledger, account, or location where supported. Correlate a log row with feed data using time, request context, identity, and destination instead of exposing full proxy credentials in a support ticket.
Transactions describe data movements and consumption records with sender/recipient scope. For non-staff callers, sender and recipient filters are constrained to the authenticated account. This is not a complete journal of allocations, purchases or expiry, and it is not generated one-for-one from request rows. Use your operation journal for quota changes, overall for traffic and durable order/ledger state for usable balance.
Every analytics request is evaluated inside the authenticated account boundary:
user_id;include_sub_users=true to overall or domains to aggregate its own activity with every direct sub-user;user_id with include_sub_users=true to aggregate a selected account and its direct sub-users;| Filter group | Values | Typical use |
|---|---|---|
| Reporting window | start, end, timezone | Reproducible billing and operational periods |
| Pagination | limit, offset | Bounded feed, log, domain, and transaction exports |
| Commercial scope | user_id, package_id, ledger_id, include_sub_users | One customer, product, purchase pool, or aggregated reseller portfolio |
| Request details | hostname, protocol | Destination investigation and HTTP/SOCKS comparison |
| Targeting | country, region, city | Inventory and routing-quality analysis |
| Failure and movement | error_code, sender_id, recipient_id, type | Error clustering and allocation audits |
Not every endpoint accepts every filter. Region requires country, and city requires country and region. Use the Analytics operations in the API Reference as the exact per-endpoint contract.
Use include_sub_users=true when a chart or destination report must represent a reseller as one commercial account. The option is available only on GET /analytics/overall and GET /analytics/domains.
For an authenticated reseller, omit user_id or pass the reseller’s own ID:
curl 'https://{api_host}/api/v1/analytics/overall' \ --get \ --header 'Authorization: Static {api_key}' \ --data-urlencode 'timezone=UTC' \ --data-urlencode 'start=2026-09-01T00:00:00Z' \ --data-urlencode 'end=2026-09-01T01:00:00Z' \ --data-urlencode 'include_sub_users=true'import { ProxyRequestClient } from "@proxyrequest/sdk";
const client = ProxyRequestClient.withApiKey( "{api_key}", { baseUrl: "https://{api_host}/api/v1" });
const result = await client.analytics.getOverall({ timezone: "UTC", start: "2026-09-01T00:00:00Z", end: "2026-09-01T01:00:00Z", includeSubUsers: true,});from datetime import datetimefrom proxyrequest_sdk import Client
with Client.with_api_key( "{api_key}", base_url="https://{api_host}/api/v1") as client: result = client.analytics.get_overall( timezone="UTC", start=datetime.fromisoformat("2026-09-01T00:00:00Z"), end=datetime.fromisoformat("2026-09-01T01:00:00Z"), include_sub_users=True, )<?phprequire __DIR__ . '/vendor/autoload.php';
use ProxyRequest\Client;
$client = Client::withApiKey( '{api_key}', 'https://{api_host}/api/v1');
$result = $client->analytics()->getOverall( timezone: 'UTC', start: '2026-09-01T00:00:00Z', end: '2026-09-01T01:00:00Z', includeSubUsers: true,);{ "count": 1, "next": null, "previous": null, "results": [ { "timestamp": "2026-09-01T00:00:00Z", "data": 1073741824, "requests": 120 } ], "timezone": "UTC", "start": "2026-09-01T00:00:00Z", "end": "2026-09-01T01:00:00Z"}Replace placeholders in braces with your values. Responses use synthetic example data.Install SDKsAPI reference →
A superuser must identify the account whose portfolio should be aggregated. JWT and static API-key authentication have the same scope rules:
curl 'https://{api_host}/api/v1/analytics/domains' \ --get \ --header 'Authorization: Static {api_key}' \ --data-urlencode 'timezone=UTC' \ --data-urlencode 'start=2026-09-01T00:00:00Z' \ --data-urlencode 'end=2026-09-01T01:00:00Z' \ --data-urlencode 'user_id={user_id}' \ --data-urlencode 'ordering=-data' \ --data-urlencode 'include_sub_users=true'import { ProxyRequestClient } from "@proxyrequest/sdk";
const client = ProxyRequestClient.withApiKey( "{api_key}", { baseUrl: "https://{api_host}/api/v1" });
const result = await client.analytics.listDomains({ timezone: "UTC", start: "2026-09-01T00:00:00Z", end: "2026-09-01T01:00:00Z", userId: "{user_id}", ordering: "-data", includeSubUsers: true,});from datetime import datetimefrom proxyrequest_sdk.models import AnalyticsDomainsRetrieveOrderingfrom uuid import UUIDfrom proxyrequest_sdk import Client
with Client.with_api_key( "{api_key}", base_url="https://{api_host}/api/v1") as client: result = client.analytics.list_domains( timezone="UTC", start=datetime.fromisoformat("2026-09-01T00:00:00Z"), end=datetime.fromisoformat("2026-09-01T01:00:00Z"), user_id=UUID("{user_id}"), ordering=AnalyticsDomainsRetrieveOrdering("-data"), include_sub_users=True, )<?phprequire __DIR__ . '/vendor/autoload.php';
use ProxyRequest\Client;
$client = Client::withApiKey( '{api_key}', 'https://{api_host}/api/v1');
$result = $client->analytics()->listDomains( timezone: 'UTC', start: '2026-09-01T00:00:00Z', end: '2026-09-01T01:00:00Z', userId: '{user_id}', ordering: '-data', includeSubUsers: true,);{ "next": null, "previous": null, "timezone": "UTC", "start": "2026-09-01T00:00:00Z", "end": "2026-09-01T01:00:00Z", "results": [ { "hostname": "example.com", "data": 1073741824, "requests": 120 } ]}Replace placeholders in braces with your values. Responses use synthetic example data.Install SDKsAPI reference →
The response shape does not change. overall sums every account into the existing time buckets; domains combines identical hostnames before ordering and pagination. Date, package, hostname, search, ordering, limit, and offset filters continue to apply to the combined data.
Historical activity remains attributable through the reseller relationship, so the aggregate includes traffic generated during the selected window by sub-users that have since been deleted. It does not add a per-user breakdown. Query an individual user_id without the option when you need a single account, and use feed or logs for request-level investigation.
For regular users the option is ignored. When a reseller selects one of its sub-users through user_id, the request remains scoped to that sub-user even if the option is present. A superuser request without user_id remains scoped to the authenticated superuser; it is not a global analytics query.
Protect gross margin
Compare traffic by customer, package, and destination with the commercial plan to identify costly workloads and plans priced below their usage shape.
Improve support
Move from “the proxy failed” to a bounded request, time, protocol, location, pool, and error code that engineering can reproduce.
Plan capacity
Combine active connections with traffic trends to detect concurrency saturation separately from byte-volume growth.
Reconcile resellers
Compare sub-user activity and transaction history with your local customer, allocation, invoice, and webhook projections.
Keep three sources separate: invoices describe purchases, your durable operation journal describes quota grants/reductions, and traffic analytics describes consumption. Current allocation writes produce administrative audit events; do not assume each one also appears in the optional legacy transactions feed. Expiration is another reason usable balance can fall without traffic.
For a finite root pool, reason about opening usable balance + purchased additions − all traffic charged to that pool − expired unused data, with any explicit corrections and accounting delay recorded separately. The root user’s own data_spent is not all shared-pool consumption. For a virtual child, REST remaining is max(assigned data - child usage, 0) and still depends on the parent pool. See the balance field map.
The public usable-ledger list cannot reconstruct a complete past expiration journal after buckets disappear. Persist the purchase/deadline context your own billing requires; do not label an unexplained balance decrease as customer traffic.