Traffic analytics: what the numbers support
Read measured web traffic as evidence: separate volume, acquisition quality, funnel shape, retention, revenue, and instrumentation health without turning correlation into causation.
What Echo measures#
Open /analytics for the aggregate view. Echo groups accepted production events by site and selected date range after removing internal paths, staff, test, QA, and synthetic traffic through the shared exclusion layer. echo-cli analytics 30 returns the bounded underlying web and mobile event projections without user or anonymous identifiers; echo-cli chat-latency 30 and Echo Desktop's Chat latency page return only production per-site response aggregates.
For first-party web events, an actor is user_id when present and anonymous_id otherwise. Sessions use session_id. Page, event, engagement, referrer, acquisition, lifecycle, revenue, and retention values therefore describe measured identifiers and sessions—not a census of people.
| Signal | Definition | What it supports |
|---|---|---|
Active users | Distinct measured actor identifiers in the window. | Measured reach within one site; not total market demand or exact people. |
Sessions | Distinct session identifiers. | Visit frequency and users-per-session context when read with active users. |
Engagement | Engaged sessions, duration, events, and seconds per user by page. | Which pages hold measured attention; not whether the visitor was satisfied. |
Acquisition | Channel, detail, referrer hosts, top landing pages, and UTM-linked actors. | Where measured traffic arrived from and which sources reach later outcome events. |
Web funnel | Distinct landing, identified, activated, and purchasing actors plus stage-count ratios. | Where the largest measured count or ratio change appears; not a causal conversion probability. |
Retention | Eligible first-seen actors returning on D1, D3, D7, D14, or D30. | Whether measured actors return after first use, with the eligible denominator always shown. |
Lifecycle and revenue | Paywall, checkout, trial, subscription, purchase, renewal, cancel, refund, and net revenue events. | Commercial outcomes only when event contracts and attribution coverage are healthy. |
Coverage | Instrumented sites, reporting sites, contract failures, warnings, and blockers. | Whether a business conclusion is supportable or collection must be fixed first. |
Read chat response latency#
Echo joins no customer identity into this view. It reduces chat_assistant_response and chat_assistant_response_server events by site after the same production exclusions used by the dashboard, then returns nearest-rank P50 and P95 values in milliseconds. The CLI reads every matching row of the selected window and discloses only site names, client/server row counts, and aggregate timings.
client_samples and server_samples count accepted response event rows. A blank, negative, or non-numeric timing is ignored by that metric's percentile calculation, so a row count is context for coverage rather than a guarantee that every percentile has the same denominator.
echo-cli chat-latency 7| Signal | Definition | Measured interval |
|---|---|---|
response_headers_ms | Browser request to response headers. | From immediately before POST /api/chat/send to receipt of Echo Web response headers. |
first_content_ms | Browser request to first assistant content. | From the same browser request start to the first non-empty assistant content appended from the response stream. |
response_complete_ms | Complete browser response. | From the same browser request start until the response stream has been fully read. |
backend_headers_ms | Backend request to backend response headers. | From immediately before Echo Web calls the chat backend until that backend returns response headers. |
proxy_total_ms | Complete Echo Web proxy request. | From entry into POST /api/chat/send, including authentication and request construction, until the backend response stream completes. |
Configure a deployment#
Echo contains no built-in customer, site, application, or host. A single-site web deployment sets the public collector URL, site id, site name, and base URL. A multi-site deployment supplies WEB_ANALYTICS_SITES_JSON; each entry declares its canonical id, display name, hosts, optional aliases, and collector URL. MOBILE_ANALYTICS_APPS_JSON similarly declares every iOS, Android, or macOS application, its analytics backend, canonical and legacy ids, and optional GA4 identifiers. These registries authorize collector requests and define the web sites and mobile apps shown in the dashboard.
UMAMI_AUDIT_TARGETS_JSON declares the public pages whose Umami installation Echo audits. When it is absent, Echo derives targets from NEXT_PUBLIC_UMAMI_DOMAINS. Connected Umami accounts can still add their managed sites to the report. CORS_ALLOWED_ORIGINS declares external dashboard clients; Echo also allows its own NEXT_PUBLIC_SITE_URL origin. PRODUCT_ANALYTICS_SITE_ID and the two PRODUCT_*_SNAPSHOT_EVENT_NAME values bind optional product snapshot imports, and events with those two names never count as production traffic.
What else does not count as production is the deployment's declaration; Echo builds in no list of test-looking hosts, flags or words, and the dashboard and the echo CLI read the same variables, so both report the same numbers. ANALYTICS_EXCLUDED_EVENT_NAMES, _PATHS, _HOSTS (localhost among them when local traffic should not count), _USER_IDS, _ANONYMOUS_IDS, _SESSION_IDS, _EMAILS, _EMAIL_DOMAINS and _REVENUECAT_ENVIRONMENTS are lists, JSON or comma-separated. ANALYTICS_EXCLUDED_PROPERTIES holds key=value entries (is_test=true, environment=staging) matched case-insensitively against an event's properties and properties.analytics; an entry without = is refused naming it. An event is excluded with the reason it matched (host:…, property:is_test:true), and a RevenueCat event of type TEST is RevenueCat's own test event.
Five values are decisions Echo does not make for the operator. ECHO_SIGNED_URL_TTL_SECONDS is how long every signed object and upload link stays valid; without it Echo issues no link and says the setting is missing. ECHO_LOGIN_FAILURE_LIMIT is how many failed logins in a row disable a routine account; without it the routine refuses to enqueue for the account. ECHO_LOW_BALANCE_USD is the balance below which /balances files a low-balance action; without it no action is filed and the answer says so. ECHO_CHARACTER_DAILY_ACTIONS is how many actions one character's linked accounts make in a day while the character's weekly routine has them awake (none while it says they are asleep), and ECHO_PROMOTE_PER_IDENTITY_PER_DAY how many of them may promote a product; without either the routine skips the character's accounts for the tick with the missing name as the reason, and the identity page shows it in place of the cap.
The routine rests an account on two more. ECHO_STALE_COOKIE_RETRY_HOURS is how long an account marked cookies-stale waits before the routine tries it again (a newer successful login ends the wait), and ECHO_BAN_SIGNAL_QUIET_DAYS how long a ban signal keeps an account out; without either the account is skipped for the tick with the missing name as the reason. A character is promoted only when its promotion_config states daily_promote_cap and min_hours_between_promotes; otherwise the promote action is swapped and the reason names the missing field.
Three more define measurements. ECHO_QUALIFIED_CONVERSATION_MESSAGES is how many messages make a product conversation qualified, the North Star's definition; without it the growth report is refused with that name. ECHO_VIRAL_REFERENCE_MIN_VIEWS is how many views a scraped video needs to become a viral reference (it also needs a caption), and ECHO_ENRICH_REFERENCE_COUNT how many of the best references, ranked by interactions per view, a video prompt is enriched with; without them the scrape and the enrichment are refused with the missing name.
Reference video classification reads seven more. ECHO_VIDEO_CLASSIFY_FRAMES is how many frames of a video the classifier sees, taken at the start of equal parts of it. ECHO_SCENE_CUT_SCORE and ECHO_SCENE_MORPH_CUT_SCORE are the ffmpeg scene scores (0-1) that mark a cut and a morph transition, ECHO_SCENE_MIN_SECONDS the shortest scene kept, and ECHO_SCENE_MORPH_COLLAPSE_SECONDS how close morph cuts merge into one boundary. ECHO_SCENE_SAMPLE_FPS and ECHO_SCENE_FRAME_WIDTH are the frames per second and frame width the vision scene detector is shown. Without one of them the classification or scene split is refused with the missing name; a failed frame extraction is reported with ffmpeg's reason.
Explainer video metrics read two more. ECHO_EXPLAINER_METRICS_WINDOW_DAYS is how many days after posting an explainer's TikTok numbers are still read, and ECHO_EXPLAINER_METRICS_RESCRAPE_HOURS how long the cron waits before reading the same video again; without either the cron answers 503 with the missing name. Engagement is interactions per view, every like, comment and share counted once. A count TikTok did not report is stored as null, never 0, and a video without views or with an unreported count has no engagement rate; viral references with no rate rank last. How many items one Apify run returns is the content-apify item's max_items in Skarbiec, refused by name when missing.
Two more define reporting. ECHO_ATTRIBUTION_COOKIE_MAX_AGE_SECONDS is how long the paid-ads attribution cookie lives; without it the attribution route answers 503 with the missing name. ECHO_GROWTH_TREND_DAYS is how many recent days the growth trend compares with the same number of days before them; without it the growth report is refused with that name. The web analytics API needs an explicit from and to; Umami pages and events, and the weak-pages list, show every row. Avatar generation uses the surveyed platform's measured spec and refuses a platform the survey did not measure.
NEXT_PUBLIC_SITE_URL=https://echo.example.com
NEXT_PUBLIC_BASE_URL=https://echo.example.com
NEXT_PUBLIC_ECHO_ANALYTICS_COLLECTOR_URL=https://echo.example.com/api/analytics/web/collect
NEXT_PUBLIC_WEB_ANALYTICS_SITE_ID=my-product
NEXT_PUBLIC_WEB_ANALYTICS_SITE_NAME=My Product
WEB_ANALYTICS_SITES_JSON='[{"id":"my-product","name":"My Product","hosts":["www.example.com"],"aliases":[],"collectorUrl":"https://echo.example.com/api/analytics/web/collect"}]'
MOBILE_ANALYTICS_APPS_JSON='[{"id":"my-product-ios","name":"My Product iOS","platform":"ios","analyticsBackend":"first_party","firstPartyAppId":"my-product-ios","legacyFirstPartyAppIds":[],"collectorUrl":"https://echo.example.com/api/analytics/mobile/collect"}]'
UMAMI_AUDIT_TARGETS_JSON='["https://www.example.com"]'
CORS_ALLOWED_ORIGINS=https://app.example.com
PRODUCT_ANALYTICS_SITE_ID=my-product
PRODUCT_ANALYTICS_SNAPSHOT_EVENT_NAME=product_admin_analytics_snapshot
PRODUCT_CONVERSATION_SNAPSHOT_EVENT_NAME=product_admin_conversation_snapshot
ANALYTICS_EXCLUDED_PATHS='["/internal/test-page"]'Read the web funnel exactly#
Echo counts distinct actors with page_view as landing users, identity events as identified users, activation events as activated users, and purchase events as purchase users. The four counts are computed independently inside the selected window; they are not automatically restricted to the same ordered cohort.
landing-to-identity = identified users / landing users
identity-to-activation = activated users / identified users
activation-to-purchase = purchase users / activated usersWorked example#
Suppose a 30-day site report shows 10,000 landing users, 2,500 identified users, 1,000 activated users, and 100 purchase users. Echo displays 25% landing-to-identity, 40% identity-to-activation, and 10% activation-to-purchase.
The defensible conclusion is: the largest observed count gap is between landing and identity, while the lowest displayed stage ratio is activation-to-purchase. First verify identity and purchase event coverage, then split the report by acquisition source and landing page. If coverage is sound, test one concrete landing or offer change and evaluate activation, purchase, retention, and revenue on assigned cohorts.
The report does not establish that the landing page caused the gap, that 90% of activated people abandoned purchase, or that a redesign will improve revenue. Those claims require ordered actor-level cohorts or an experiment.
Questions the data can answer#
- Is measured traffic rising or falling versus the previous matching window, and is the change concentrated in one site, source, landing page, or event?
- Which sources bring actors who activate, purchase, return, and produce net revenue—not merely page views?
- Which pages combine substantial reach with low engagement or weak later-stage outcomes and deserve an instrumentation check or experiment?
- At which measured stage does the largest count or ratio change appear: landing, identity, activation, paywall, checkout, trial, purchase, renewal, cancel, or refund?
- Do eligible cohorts return on D1, D7, and D30, and does acquisition quality persist after the first session?
- Is paid traffic linked to first-party outcomes strongly enough to discuss CAC, ROAS, and payback, or is attribution coverage the finding?
- Are missing events, non-reporting sites, contract failures, exclusion mistakes, or identifier breaks making every business conclusion premature?
Claims the data cannot make alone#
- Traffic movement does not identify its cause. Seasonality, releases, outages, campaign mix, consent, blockers, and instrumentation can move the same number.
- A referrer or UTM association is attribution evidence, not proof that the channel caused the outcome. Use a holdout or randomized experiment for incrementality.
- Anonymous and identified ids do not guarantee one stable person across devices, browsers, consent changes, or identity transitions.
- High engagement does not prove satisfaction, intent, accessibility, or product value; pair it with activation, retention, revenue, quality, and support signals.
- Umami supplies visitors, visits, pageviews, bounces, duration, pages, and events, but not identity, activation, purchase or revenue: for an Umami-only source those values show as '-' (unmeasured), and a site whose Umami read failed shows an error with no metrics rather than zero traffic. Web revenue totals add only the sites that measured revenue.
- Umami page and event rows keep unique visitors absent when the provider did not return them; event counts and pageviews are not substitutes for people. Unsupported page activation, purchase, revenue and engagement measurements remain null through the growth report. Only pages with measured activation, engagement and unique-user counts enter the weak-page ranking. Missing or malformed required Umami stats and malformed metric arrays fail the report with their cause rather than becoming zero traffic or an empty successful result.
- Traffic and revenue totals are null when no site measured them, rather than a zero invented from an empty set. The Web Funnel names how many sites lack traffic or revenue measurements, and a failed site's original read error remains visible with null counts. A total over the remaining measured sites is partial coverage, not proof of zero activity on the omitted sites.
- Small eligible cohorts and incomplete contracts do not support ranking sources or variants. Show counts with every rate and name missing data.
Decision checklist#
- Choose the site, date range, comparison window, and business question before reading a metric.
- Check reporting coverage, exclusions, contract failures, identifier continuity, and linked attribution.
- Read counts before rates and show every denominator, especially retention eligibility.
- Segment by source and landing page, then compare activation, purchase, retention, net revenue, and quality.
- Write one observation, one competing explanation, and one measurement or experiment that could separate them.
- Change a product or budget only after the outcome metric and guardrails support it.