Echo/Docs

CLI command

tracking

Declare the events each analytics source sends and judge how the stored events of a window hold to them; keep each product's metric tree with its values, anomalies and reports; follow retention cohorts by acquisition channel; take events from product backends; and keep each source's UTM vocabulary.

Invocation#

Shell
echo-cli tracking schemas list
echo-cli tracking schemas declare --app <app-id> --event <name> --properties <name,name|->
echo-cli tracking schemas remove <schema-id>
echo-cli tracking quality show --days <days>
echo-cli tracking quality volume --days <days> --history <windows> --sigmas <n>
echo-cli tracking metrics list --product <id>
echo-cli tracking metrics define --product <id> --name <name> --event <event-name> --counts events|users|visitors|sessions|sum [--value-property <name>] [--filter-property <name> --filter-value <value>] [--app <app-id>] [--parent <metric-id>]
echo-cli tracking metrics remove <metric-id>
echo-cli tracking metrics tree --product <id> --days <days>
echo-cli tracking metrics anomalies --product <id> --days <days> --history <windows> --sigmas <n> [--segment-property <name>]
echo-cli tracking reports write --product <id> --days <days>
echo-cli tracking reports list --product <id>
echo-cli tracking alerts list
echo-cli tracking alerts watch --product <id> --days <days> --history <windows> --sigmas <n> --every-hours <hours> [--segment-property <name>] --notify <user-id> --by <name>
echo-cli tracking alerts unwatch <watch-id>
echo-cli tracking alerts check
echo-cli tracking schedules list
echo-cli tracking schedules set --product <id> --days <days> --every-hours <hours> [--recipient <email>] --by <name>
echo-cli tracking schedules remove <schedule-id>
echo-cli tracking content decay --surface <slug> --days <days> --keep <share>
echo-cli tracking content refreshes --surface <slug> [--status open|applied|dismissed]
echo-cli tracking content refresh --post <post-id> --days <days> --keep <share> --by <name>
echo-cli tracking content apply --id <refresh-id> --by <name>
echo-cli tracking content dismiss --id <refresh-id> --by <name>
echo-cli tracking content returns --surface <slug> --days <days> --signup-event <name>
echo-cli tracking content predict --post <draft-id> --days <days> --sigmas <standard-errors>
echo-cli tracking attribution show --days <days> --conversion-event <name> --value-property <name> [--subject <id>]
echo-cli tracking identity show --id <user-id|anonymous-id|revenuecat-id>
echo-cli tracking cohorts show --app <app-id> --weeks <weeks>
echo-cli tracking events report (--site <site-id> | --app <mobile-app-id>) --event-id <id> --event <name> --occurred-at <iso-time> (--user <id> | --anonymous <id>) [--session <id>] [--url <page address>] [--referrer <address>] [--screen <screen name>] --properties <json>
echo-cli tracking keys list [--source <site-or-app-id>]
echo-cli tracking keys issue --source <site-or-app-id> --label <text> --by <name>
echo-cli tracking keys revoke --id <key-id> --by <name>
echo-cli tracking utm list --app <app-id>
echo-cli tracking utm add --app <app-id> --parameter <utm_name> --value <value> --meaning <text>
echo-cli tracking utm remove <value-id>
echo-cli tracking utm build --app <app-id> --url <https-url> <utm_parameter=value> …
echo-cli tracking utm stray --days <days>

Inputs and output#

schemas list writes every declared event (id, app_id, event_name, required_properties, created_at) by source then event; declare and remove write the one declaration. quality show writes { since, sources, findings, silent }: every source seen in the window with its event count, how many of those a backend reported (from_server) and whether it declares schemas; one finding per source, event and problem — "event not declared for this source" or "missing property <name>" — with how often it happened and one example event (event_id, app_id, event_name, properties, server_origin); and every declaring source that sent no event in the window. events report writes { event_id, stored, already_stored_by }: stored true when the event was stored now, otherwise already_stored_by names who stored that event_id first — browser or server.

State effect#

Every verb calls Echo Web's authenticated /api/analytics operation with ECHO_INTERNAL_BEARER at ECHO_WEB_BASE_URL; the dashboard's /tracking screen and Echo Desktop's Tracking destination call the same operations (Echo Desktop reads and changes schemas, quality and volume drops, backend source keys, the UTM vocabulary, identity, cohorts, the metric tree with its anomalies, alerts, reports and report schedules, content decay and returns, and draft predictions; events report stays with product backends, which report with their own source key or with ECHO_INTERNAL_BEARER). A source is the app_id the web and mobile collectors store. A source is judged only once it declares at least one event, so declaring is how a source starts being checked; --properties - declares an event that must carry no particular property. quality show reads every web and mobile event of the last --days days on each call, so a declaration added later also judges the events stored before it; it writes nothing.

Refusals#

  • A wrong invocation is refused as a usage error before anything is sent: "tracking takes <every noun listed above, separated by commas>; got <word>", "tracking <noun> takes <the usage of every verb of that noun>; got <word>", "tracking <noun> <verb> does not take <flag>; it takes …", "<flag> needs a value", "tracking schemas declare needs <flag>" for each of --app, --event and --properties, "tracking schemas remove needs a schema id, as tracking schemas list prints it", "tracking quality show needs --days <days>: the window to judge", "tracking metrics <verb> needs --product <id>, as echo-cli products prints it", "tracking metrics define needs <flag>" for each of --product, --name, --event and --counts, "tracking metrics remove needs a metric id, as tracking metrics list prints it", "tracking metrics tree needs --days <days>: the window to compute", "tracking cohorts show needs --app <app-id>", "tracking cohorts show needs --weeks <weeks>: how many weeks to follow", "tracking content predict needs <flag>" for each of --post, --days and --sigmas.
  • Echo Web's refusal is printed as "Echo Web refused <method> /api/analytics/… with HTTP <status>: <its answer>": a bad request with "app_id is required: the source the collectors store events under", "event_name is required: the event the source sends", "required_properties is required: …", "the property <name> is named twice; name each once" or "days must be a positive whole number: the window to read"; a conflict with "<app> already declares <event> as schema <id>; remove it first"; not found with "no event schema has id <id>; echo-cli tracking schemas list lists them"; a page of events that stops before the counted total fails with "the database counted <n> <table> since <time> and stopped answering after <m>".
  • quality volume writes { windows, drops }: the start of each window, oldest first, and every source whose event count in the latest window of --days days lies below the mean less --sigmas standard deviations of its counts in the --history windows before it, with app_id, events (the latest count), mean, low (the edge of the band) and history (the earlier counts, oldest first), the steepest fall first. All three numbers are the caller's; Echo assumes none. A source that sent nothing in the latest window falls to zero like any other; a source seen only in the latest window has no history and is not judged. The dashboard's /tracking screen (Volume drops), Echo Desktop's Tracking destination and echo-mcp (echo_volume_drops) read the same GET /api/analytics/quality/volume. Usage errors: "tracking quality volume needs <flag>" for each of --days, --history and --sigmas. Echo Web answers a bad request with "<name> is required", "days must be a positive whole number: the length of each window", "history must be a positive whole number: how many earlier windows give the expected volume" or "sigmas must be a positive number: how many standard deviations below the mean a drop lies".
  • metrics define stores one metric of a product: it counts the stored events named --event, from every source or only --app, as events, distinct users, distinct anonymous visitors or distinct sessions (--counts), or with --counts sum adds the number each such event holds in its --value-property (an event whose property holds no number adds nothing; it is not read as zero); with --filter-property and --filter-value it counts only the events whose property holds that value; and it feeds the metric --parent names; the product's one metric without --parent is its North Star. metrics list writes the product's metrics in the order they were defined, each with value_property, filter_property and filter_value (null when not set); metrics remove deletes one no other metric feeds. metrics tree writes { since, tree }: the North Star with its value over the last --days days and, nested under it, every metric feeding it with its own value, each counted from the stored web and mobile events on every call; anomalies, reports, OKR progress, the effect report and market sizing value metrics the same way. Echo Web answers a bad request with "<field> is required and may not be blank", "counts must be one of events, users, visitors, sessions, sum, not <value>", "value_property names the property a sum adds, and only counts sum takes one", "filter_property and filter_value come together: the property an event must carry and the value it must hold" or "metric <id> is fed by <names>; remove those first"; a conflict with "product <id> already has the metric <name> as <id>" or "product <id> already has its North Star, <name>; name the metric it feeds with --parent"; not found with "product <id> has no metric <id>; echo-cli tracking metrics list --product <id> lists them", "no metric has id <id>; …" or "product <id> has no North Star yet; define one with echo-cli tracking metrics define --product <id> without --parent".
  • alerts watch declares a product's metric alert watch: the window of --days its metrics are valued over, the --history earlier windows (at least two, since one has no spread) whose mean ± --sigmas standard deviations make each metric's range, how often in --every-hours Echo checks, optionally the --segment-property each alert also splits the metric's change by (as metrics anomalies --segment-property splits it), the user --notify whose pending actions receive the alerts, and --by who declares it; a product has one watch. alerts list writes { watches, alerts }: every watch with segment_property (null when it names none) and when it was last checked, and every alert newest first (watch_id, metric_id, window_start, value, mean, low, high, segments with the change per source, property_segments with the change per value of the watch's property — the events without it being one segment named no <property> — or null when the watch names none, pending_action_id, raised_at). The alert's pending action names the same sources and property values. alerts unwatch removes a watch with its alerts. alerts check checks every watch now and writes one check per watch: alerted (with the alerts it raised), within, or unchecked with the error that stopped it. Echo Web's hourly /api/cron/metric-alerts checks each watch whose last check is at least its every_hours ago; a metric outside its range raises one alert per window, so a check run twice alerts once. Every number is the operator's; Echo assumes none. The dashboard's /tracking screen (Metric alerts) and Echo Desktop's Tracking destination read and change the same /api/analytics/metrics/alerts. Usage errors: "tracking alerts watch needs <flag>" for each of its required flags and "tracking alerts unwatch needs a watch id, as tracking alerts list prints it". Echo Web answers a bad request with "<field> is required: …", "days must be a whole number of at least 1: …", "history must be a whole number of at least 2: …", "sigmas must be a positive number: …", "every_hours must be a whole number of at least 1: …" or "segment_property, when sent, must name the event property each alert splits the metric's change by; got <value>"; a conflict with "product <id> is already watched (<id>), declared by <name>; remove it first"; not found with "no metric alert watch has id <id>".
  • schedules set declares how often a product's metric report is written: the --days each report covers, every --every-hours, optionally the --recipient each written report is delivered to — an email address, or an HTTPS webhook address such as a Slack channel's incoming webhook — and --by who declares it; a product has one schedule. schedules list writes every schedule with recipient, attempted_at, report_id (the report it last wrote), error (why the last write failed, or null), sent_at (when a report was last delivered) and send_error (why the last delivery failed, or null). schedules remove deletes one. Echo Web's hourly /api/cron/metric-reports writes the report of every schedule whose last attempt is at least its every_hours ago, through the same writeReport reports write uses, so its commentary is refused the same way when it cites a number the table does not hold; the refusal is kept on the schedule as its error and the next run tries again. When the schedule names an address, the written report — its table of each metric beside the window before with the change, then the commentary — is emailed as plain text from ECHO_REPORT_FROM through Echo's Resend integration; when it names a webhook, the webhook is sent one POST of JSON { text, report }, text being that same plain text (which a chat channel's incoming webhook shows) and report the stored report with its rows, and counts as delivered once it answers a success status. A webhook address is kept as given and is itself the credential, so keep it as secret as one. A suppressed address, a missing ECHO_REPORT_FROM, Resend's refusal, "the webhook answered HTTP <status>: <body>" or "the webhook could not be reached: <why>" is kept as send_error while the report stays written. The dashboard's /tracking screen (Report schedules) and Echo Desktop's Tracking destination (Metric reports) read and change the same /api/analytics/reports/schedules. Usage errors: "tracking schedules set needs <flag>" for each of its required flags and "tracking schedules remove needs a schedule id, as tracking schedules list prints it". Echo Web answers a bad request with "product_id is required: …", "days must be a positive whole number: …", "every_hours must be a positive whole number: …", "address must be one email address, a local part and a domain around one @; got <value>", "recipient <value> is a plain http address; a webhook must be HTTPS, since the report travels to it", "recipient <value> starts as an HTTPS webhook address but is not one" or "declared_by is required: …"; a conflict with "product <id> already has a report schedule (<id>), declared by <name>; remove it first"; not found with "no report schedule has id <id>".
  • utm add declares one value a UTM parameter may take where a source's links land, with what it means; the parameters a vocabulary may declare are the UTM parameters the attribution collector reads (utm list answers them beside the values). utm remove deletes one. utm build writes the --url with every utm_parameter=value pair set, each refused unless the source declares it. Paid campaigns created on the paid ads screen follow the same vocabulary: POST /api/paid-ads/campaigns takes link_source, the analytics source the campaign's ads land on, and utm_medium, and its links carry utm_source (the ad platform, meta or appleads), that utm_medium and utm_campaign (the campaign's name), each of which link_source must declare — otherwise the campaign is refused before the ad platform is called with "<app> does not declare <parameter>=<value>, …; declare each with echo-cli tracking utm add --app <app> before creating the campaign", or "link_source is required: …" / "utm_medium is required: …" when either is missing. utm stray writes { since, stray }: every UTM value an event of a declaring source carried in the last --days days without the source declaring it, with how many events carried it and one example event id; a value declared later clears the events that carried it before. Usage errors: "tracking utm <verb> needs --app <app-id>", "tracking utm add needs <flag>" for each of --app, --parameter, --value and --meaning, "<word> is not a utm_parameter=value pair", "tracking utm build needs --url <https-url>", "tracking utm remove needs a value id, as tracking utm list prints it", "tracking utm stray needs --days <days>: the window to check". Echo Web answers a bad request with "parameter must be one of <parameters>, not <name>", "url must be an HTTPS address, not <url>", "name at least one of <parameters>" or "<app> does not declare <parameter>=<value>; add it with echo-cli tracking utm add first"; a conflict with "<app> already declares <parameter>=<value> as <id>"; not found with "no UTM value has id <id>; echo-cli tracking utm list --app <app-id> lists them".
  • cohorts show writes { since, cohorts } for one web or mobile source over the last --weeks ISO weeks: one cohort per first-seen week and acquisition channel (week, channel, size) with active, the count of its visitors who sent any event in each week after it, the first entry being the cohort week itself. A visitor is one person: every identifier the identity edges link (as identity show resolves them) and every event carrying both a user id and an anonymous id counts as the same visitor; the channel is the one growth analytics gives the visitor's first event in the window — for a web event paid per ad platform, utm_<source>, referral or direct_or_owned; for a mobile event paid_<platform> for the ad platform its properties carry, else paid_<platform> for the platform of the visitor's earliest stored install attribution (ad_attribution_events joined to the visitor through the identity edges), and only without either the plain mobile channel. Echo Web answers a bad request with "app_id is required: the web or mobile source whose visitors to follow" or "weeks must be a positive whole number: how many weeks to follow".
  • events report is how a product's backend reports an event itself (the same operation is POST /api/analytics/server/collect with ECHO_INTERNAL_BEARER), so blockers and cookie limits in the browser, or an app closed or offline before it sent the event, cannot lose it. --site reports a web event of a declared web analytics site; --app reports a mobile event of a configured mobile analytics app (its first-party app id, stored with the app's platform and --screen as its screen name), judged by the same event contract the mobile collector applies. It must carry the event_id the browser or app uses for the same event: the browser and app collectors skip an event_id already stored and this operation skips one they already sent, so the event is stored once whichever arrives first, and already_stored_by names browser, app or server; a stored backend event has server_origin true, --url stores the address of the page a web event happened on with its path, as heatmap page and affiliates read them, and --referrer the address the visitor came from, as seo updates impact reads it. Usage errors: "tracking events report needs <flag>" for each of --event-id, --event, --occurred-at and --properties, "tracking events report needs exactly one of --site <site-id> (a web event) and --app <mobile-app-id> (a mobile event)", "--properties is not JSON: <cause>". Echo Web answers a bad request with "name exactly one of site_id (a web event) and app_id (a mobile event)", "<site> is not a declared web analytics site", "<app> is not a configured mobile analytics app", "<field> is required and may not be blank", "occurred_at must be an ISO 8601 time, not <value>", "user_id or anonymous_id is required: the person the event belongs to", "url must be the absolute address of the page the event happened on; got <value>", "referrer must be the absolute address the visitor came from; got <value>" or "properties is required: a JSON object, {} when the event carries none".
  • keys issue gives a product's backend its own credential for events report's operation: a key (echo_src_ followed by random hex) for one web analytics site or mobile analytics app (--source), with a --label naming the backend that holds it and --by who issues it, and writes { key, stored } — the key this once, since Echo keeps only its SHA-256 (stored: id, source_id, label, key_sha256, created_by, created_at, revoked_by, revoked_at). The backend then calls POST /api/analytics/server/collect with Authorization: Bearer <key> instead of ECHO_INTERNAL_BEARER, and may report only for that source. keys list writes every key, of --source when named, newest first, never the key itself; keys revoke --id revokes one for good, naming --by who did. The dashboard's /tracking screen (Backend source keys) and Echo Desktop's Tracking destination issue, list and revoke the same /api/analytics/source-keys, and echo-mcp lists them as echo_list_source_keys. Usage errors: "tracking keys issue needs <flag>" for each of --source, --label and --by, "tracking keys revoke needs <flag>" for each of --id and --by. Echo Web answers a bad request with "source_id is required: …", "label is required: …", "id is required: …", "created_by is required: …" or "revoked_by is required: …" (an internal caller names who acts), or "source key <id> was already revoked by <name> at <time>"; not found with "no source key has id <id>; echo-cli tracking keys list lists them". The collect operation refuses a key as forbidden with "the source key was never issued; echo-cli tracking keys issue issues one", "source key <id> (<label>) was revoked by <name> at <time>" or "source key <id> (<label>) reports for <source>, not <source>".
  • metrics anomalies reads the product's metrics over the latest window of --days days and the --history windows of the same length before it, and writes { windows, anomalies }: the start of every window, and every metric whose latest value lies outside the mean of the earlier windows plus or minus --sigmas standard deviations (metric_id, name, value, mean, low, high) with segments, the change per source (app_id, value, mean, change), largest first; for a metric counting events the changes sum to the whole deviation. With --segment-property, property_segments splits the change by the value each event holds in that property as well (segment, value, mean, change), the events without the property being one segment named no <property>; without it property_segments is null. All three numbers are the caller's. Usage errors: "tracking metrics anomalies needs <flag>" for each of --days, --history and --sigmas. Echo Web answers a bad request with "<name> is required", "days must be a positive whole number: the length of each window", "history must be a positive whole number: how many earlier windows give the expected range", "sigmas must be a positive number: how many standard deviations the range spans", "segment_property, when sent, must name the event property to split the change by" or "product <id> has no metrics; define them with echo-cli tracking metrics define".
  • reports write computes every metric of the product's tree over the last --days days and the --days days before (metric, counts, value, previous, change), then one row per acquisition channel of the web sources the product's metrics name (metric "channel <name>", counts sessions: every web session of those sources in each window, on the channel its first event came from — paid_<platform>, utm_<source>, referral or direct_or_owned — most sessions first; a product whose metrics name no source has none), then, for every adaptive experiment a hypothesis of the product is linked to (echo-cli hypotheses link links one), one row per variant counting assignments (metric "experiment <surface key> variant <key>": the subjects assigned that variant in each window) and, when the experiment's reward spec declares its reward event and window, a row of the same metric counting "conversions (<reward event>)": those of the window's assigned subjects who sent the reward event, in the web or mobile events, within the reward window after their assignment, as experiments outcomes counts them (a subject assigned near the end of the latest window may still convert after the report is written); an experiment declaring no reward has assignment rows only. The route ECHO_REPORT_ROUTE declares writes commentary through Brama, and both are kept; commentary that cites a number neither the table nor the window length holds is refused with "the commentary cites <numbers>, which the report's table does not hold; nothing was stored". reports list writes the product's reports newest first, as written. Usage errors: "tracking reports <verb> needs --product <id>, as echo-cli products prints it", "tracking reports write needs --days <days>: the window to report on". Echo Web answers a bad request with "days must be a positive whole number: the window to read", not found with "product <id> has no metrics to report; define them with echo-cli tracking metrics define", fails with "the report route <route> declined to write the commentary" or "the report route <route> wrote an empty commentary", and a deployment without ECHO_REPORT_ROUTE answers that the setting is not configured.
  • content decay writes { since, split, posts } for one blog surface: every published post whose distinct sessions on its page (the surface's canonical host and /blog/<slug>) in the last --days days fell below --keep times its sessions in the --days days before (post_id, slug, title, latest, earlier), steepest fall first; a post with no earlier sessions is not listed. The window and the share are the caller's. Usage errors: "tracking content decay needs <flag>" for each of --surface, --days and --keep. Echo Web answers a bad request with "<name> is required", "days must be a positive whole number: the window to read" or "keep must be a positive number: the share of earlier visits a post must keep", and not found with "no blog surface is named <slug>; echo-cli blogs lists the surfaces posts belong to". content refresh drafts a rewrite of a published --post that content decay lists for --days and --keep, through the Brama route Echo Web's ECHO_REFRESH_ROUTE declares, given the post and both windows' sessions, and keeps it beside the post in blog_refresh_drafts — the live post does not change — writing the draft: id, post_id, from_revision (the post's revision it was written from), window_days, latest_sessions, earlier_sessions, title, description, body_markdown, route, status open, created_by, decided_by and decided_at (null) and created_at. content refreshes writes a surface's drafts, newest first, of --status when named. content apply writes the open draft's title, description and body into its post as a new revision, only while the post is still at from_revision, checks a published post against its product's glossary as any edit of it is, asks the landing to revalidate the page and writes { refresh, revision, revalidation }; content dismiss closes the draft without touching the post and writes { refresh }; both name who decides. The /tracking screen (under Posts losing visits) and Echo Desktop's Tracking destination (What posts do) draft, read, apply and dismiss the same way, and echo-mcp reads them as echo_content_refreshes. Usage errors: "tracking content <verb> needs <flag>". Echo Web answers a bad request with "post <id> is <status>; only a published post loses visits to refresh", "post <id> kept at least <keep> of its sessions over the last <days> days against the <days> before, so it is not decaying", "status must be one of open, applied, dismissed; got <value>", "decision must be apply or dismiss; got <value>", "refresh draft <id> is <status>, decided by <who> at <time>" or "post <id> is at revision <n>, not <m> the draft was written from; dismiss it and draft again"; a conflict with "post <id> already has open refresh draft <id>; apply or dismiss it first"; not found with "no blog post has id <id>; echo-cli blogs lists them" or "no refresh draft has id <id>"; a rewrite holding a banned phrase of the surface's product as unprocessable with "the refresh uses banned phrases of the surface's product, so it was not kept: <every occurrence>"; and a deployment without ECHO_REFRESH_ROUTE fails naming the setting.
  • content returns writes { since, posts } for one blog surface over the last --days days: every published post with landed, the visitors whose first event on the surface's host in the window was that post's page; signed_up, how many of them sent the --signup-event at or after that landing; revenue, what they paid at or after that landing per currency (never converted), from every payment stored in the window — the web and mobile events with a positive revenue property and a currency, as the Stripe and RevenueCat webhooks record them; and payers, how many of them paid. Most signups first; posts nobody landed on first are left out. A visitor is one person, counted as cohorts show counts them, so a payment recorded under the identifier they signed in with counts for the post they landed on anonymously. Usage errors: "tracking content returns needs <flag>" for each of --surface, --days and --signup-event. Echo Web answers a bad request with "<name> is required" or "days must be a positive whole number: the window to read", and not found with "no blog surface is named <slug>; echo-cli blogs lists the surfaces posts belong to".
  • content predict writes the draft --post's predicted sessions over its first --days days once published: post_id, surface, days, sigmas, sessions (the mean of the distinct sessions each published post of the draft's surface, published at least --days days ago, drew on its page — the surface's canonical host and /blog/<slug> — in its own first --days days), low and high (that mean ± --sigmas standard errors of it; null from a single post, which gives no spread), interval_method (how the interval was measured, or why there is none) and peers, every post it rests on (post_id, slug, title, published_at, sessions). Nothing is stored; the Predict a draft section of the tracking screen and of Echo Desktop's Tracking destination read the same, and echo-mcp reads it as echo_predict_draft. Usage errors: "tracking content predict needs <flag>" for each of --post, --days and --sigmas. Echo Web answers a bad request with "post_id is required: …", "days must be a positive whole number: …", "sigmas must be a positive number: how many standard errors the interval spans" or "post <id> is <status>; only a draft is predicted, and a published post's own visits are what echo-cli tracking content returns reads", and not found with "no blog post has id <id>; echo-cli blogs lists them" or "no post of <surface> was published at least <days> days ago, so none has a whole first window to predict from".
  • attribution show writes { since, models, conversions, value, channels, removal_effects, unvalued_event_ids, subject } over the web events of the last --days days; the Attribution section of the tracking screen and of Echo Desktop's GEO screen reads the same. A visitor is one person, counted as cohorts show counts them; each of their sessions is a touch on the channel its first event came from (paid per ad platform, utm_<source>, referral or direct_or_owned, as cohorts name channels), except that a referral from a host the deployment declares as an AI assistant in ECHO_AI_REFERRER_HOSTS_JSON (as geo ai-referrals counts them) is its own channel ai_<assistant>, so each assistant is credited apart from referrals; an event without a session is a touch of its own. Each ad attribution of the window the mobile attribution path recorded at install (not the web collector, whose clicks are already sessions) that names an ad platform is a touch of its own on paid_<platform>, with its campaign as the detail, so a person an app install ad acquired carries it. Revenue by channel under these models (revenue channels --model) names AI assistants and install ads the same way. A conversion is an event named --conversion-event, worth the number its properties hold under --value-property; its touches are the visitor's sessions and install attributions that began at or before it. channels gives each channel's credit under first_touch (all of a conversion's value to its first touch), last_touch (to its last), linear (split evenly over every touch) and markov, the data-driven model: every conversion's path (the channels of its touches, in order, ending in the conversion) and every never-converting visitor's path (the channels of all their touches, ending without one; a person seen only through install attributions included) make a first-order Markov chain, in which each state moves to the next channel, the conversion or the end as often as the paths do; the chance of converting is the chance of reaching the conversion from the start, a channel's removal effect is the share of that chance lost when every move into it ends the path, and each conversion's value is split over the channels of its own touches in proportion to their removal effects. removal_effects gives conversion_probability and each channel's effect. So every model's credits sum to the conversions' value; a conversion event whose value property holds no number is listed in unvalued_event_ids and credited nowhere. With --subject (a user id or anonymous id), subject lists that visitor's conversions with every touch and each model's credit. Usage errors: "tracking attribution show needs <flag>" for each of --days, --conversion-event and --value-property. Echo Web answers a bad request with "<name> is required" or "days must be a positive whole number: the window to read", and not found with "no web event since <time> belongs to <subject>; it names no visitor of the window"; a deployment without ECHO_AI_REFERRER_HOSTS_JSON fails naming the setting.
  • identity show follows the identity edges the web and mobile collectors record at sign-in (each linking a user id with an anonymous id or a RevenueCat app user id) from the --id given until no new identifier turns up, and writes { identifiers, events }: every user_id, anonymous_id and revenuecat_app_user_id found, and every web and mobile event of those users and anonymous ids (table, event_id, app_id, event_name, occurred_at), oldest first. An edge recorded later also joins the events stored before it. Usage errors: "tracking identity show needs --id <identifier>". Echo Web answers not found with "no identity edge names <identifier>; it was never seen at a sign-in".