Run your workspace
Revenue attribution
Revenue attribution answers the question every price objection hides behind: what did the AI employee actually contribute? Instead of "you had 93 conversations", the platform records every business outcome β a WooCommerce order, a Calendly booking, a lead marked won β and links orders back to the conversations that drove them, in two honest tiers that are never summed together.
The two tiers
| Tier | Requires | Window |
|---|---|---|
| Direct | The assistant recommended a product, the visitor clicked its card, and an order containing that product followed. Every direct euro has a visible chain of evidence: conversation β click event β order line. | 7 days (configurable) |
| Influenced | The same visitor had a conversation before ordering, but the specific product can't be tied to specific advice. Reported as context, never as proof. | 30 days (configurable) |
An order that qualifies for both tiers counts once β as direct. When several conversations precede an order, the last touch wins for influenced; for direct, the click-bearing conversation wins even when a later click-less one exists (evidence beats recency). No identity match means the order stays unmatched β there is no fuzzy guessing, by design.
How an order is linked to a conversation
Identity keys, strongest first:
- Conversation cookie β at checkout the WordPress
plugin stamps the widget's own first-party cookies
(
pb_anon_id,pitchbar_conv_id) onto the order as meta. Same browser, deterministic. - Visitor id β the widget's 1-year anonymous id, matched through the visitor record.
- Logged-in customer β the plugin's ShopperToken
already carries
wp_user_idonto the conversation; the order's customer id matches across devices. - Hashed e-mail β the order's billing e-mail as a
sha256hash, compared against captured leads. The raw address never leaves the shop and is never stored on the outcome row.
Honesty rules, built in
- Direct and influenced totals are never added into one figure.
- Refunds and cancellations reduce or reverse attributed value automatically; the original value stays on the row for audit.
- A recorded match is never rewritten by a webhook retry, a later conversation, or a window change β windows apply to new orders only.
- Unmatched is a correct answer, not a failure.
Requirements
- WooCommerce shops need the WordPress plugin v2.1.0+, which adds the order hooks and the checkout identity stamping.
- Calendly bookings and leads marked won in the inbox create conversation-linked outcomes automatically β no extra setup.
The report page
Analytics β Revenue
(/app/analytics/attribution) is the operator view.
Filter by agent and period; everything on it is read-only.
It opens with the funnel, because that part is measurable before any shop is connected:
Conversations β Reached the shop β Outcomes β Attributed revenue. "Reached the shop" counts the conversations in which a visitor clicked a product the assistant recommended β a real engagement figure that needs no shop integration at all.
Below it, the two tiers are shown side by side and never added together, followed by unmatched orders, refunded orders (counted, excluded), bookings and won leads. The Evidence list at the bottom shows every attributed outcome with the reason it was attributed β the clicked product for direct matches, the identity key for influenced ones β and links straight to the conversation.
If no shop is connected, the revenue figures show a dash and the page says so explicitly. That is a setup state, not a zero result: click-throughs, bookings and won leads keep being tracked, and the revenue columns fill in by themselves once orders start arriving β the page does not change.
Reading the numbers from the console
The same figures are available as an artisan command, which is also the hand-audit surface used before trusting a new shop's data:
php artisan attribution:report --agent=<uuid> --days=30
It prints per-tier totals, the count of unmatched and reversed orders, booking / won-lead counts, and one evidence line per direct match so each attributed order can be verified by hand against the real shop before any client sees a number.
Configuration
| Env | Default | Meaning |
|---|---|---|
ATTRIBUTION_DIRECT_WINDOW_DAYS |
7 | Max days between the product click and the order. |
ATTRIBUTION_INFLUENCED_WINDOW_DAYS |
30 | Max days between the conversation and the order. |