URL: /plays/account-visits · Id: `play:account-visits`

# Account visits

> Finds the fitting companies behind visits to your own buying pages and writes to the right person there, from facts, never from the visit.

Finds the fitting companies behind visits to your own buying pages and writes to the right person there, from facts, never from the visit.

```text title="Set it up · Ask"
Be our SDR for site visits: when a property manager that fits reads our pricing or setup pages, find who owns renewals there and write once, from a public fact, never from the visit. Top accounts go out as me. Show me what’s missing; don’t send.
```

```text title="Run one · Ask"
Hand the latest company that read our buying pages to the SDR agent and show me what it chose and why. Don’t send.
```

```ts title="Run one · SDK"
import { $ } from 'startup-builder'

const { events: [last] } = await $.Event.list({ where: 'name in ("Visit.recorded", "Visitor.identified")', limit: 1 })   // { play } compiled to this Play’s Trigger Events
const { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' })   // the same Event again, in try mode · Not live yet, gaps #7
const { decisions: [decision] } = await $.Decision.list({ where: `on = "${subject}"` })   // what it chose, and why · Not live yet, gaps #7
const { actions } = await $.Action.list({ where: `on = "${subject}"` })   // what it did, with its checks · Not live yet, gaps #7
return { decision, actions }
```

```json title="Run one · Response · sample"
{
  "decision": {
    "$id": "https://api.sb/leaseline.app/decisions/decision_455",
    "$type": "Decision",
    "choice": "write-to-them",
    "reason": "Fernhill Property Group read pricing on 2 days in 4 (7 points, confirmed on 2 networks), and its careers page lists 2 leasing coordinator openings",
    "stakes": "low",
    "options": [
      "write-to-them",
      "write-as-you",
      "ads-only",
      "to-their-csm",
      "not-now",
      "let-it-go"
    ],
    "by": "worker_2",
    "on": "organization_131",
    "expected": "a qualified response from Fernhill within 30d",
    "reopensWhen": "no inbound Message from contact_14 within 30d"
  },
  "actions": [
    {
      "$id": "https://api.sb/leaseline.app/actions/action_1",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_2",
      "verb": "Organization.get",
      "checks": []
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_2",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_2",
      "verb": "Contact.enrich",
      "checks": [
        {
          "check": "customer-collision",
          "status": "pass"
        }
      ]
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_3",
      "$type": "Action",
      "status": "pending",
      "reason": "awaitingTime",
      "mode": "try",
      "by": "worker_2",
      "verb": "Message.schedule",
      "checks": [
        {
          "check": "owned-by-a-person",
          "status": "pass"
        },
        {
          "check": "hold",
          "status": "pass"
        },
        {
          "check": "decay",
          "status": "pass"
        },
        {
          "check": "visit-in-copy",
          "status": "pass"
        },
        {
          "check": "approved-pages",
          "status": "pass"
        }
      ]
    }
  ]
}
```

`action_3` is touch 1 to Marta Silva (`contact_14`), Fernhill’s head of operations, held until 08:40 her time; touch 2 waits in the same thread for 6 days and drops if the stack decays first.

`18.2 qualified responses per 100 against 2.9 before · before-after, not proof · n 22 · path → arr`

| Try another: the visiting company | Choice | Reason |
| --- | --- | --- |
| Fernhill Property Group: pricing on 2 days in 4, 2 leasing roles open | `write-to-them` | 7 points, confirmed, with a public fact to write from |
| Calloway Residential: pricing and the security page, 900 units | `write-as-you` | a top-tier account: it goes out as Dana |
| Northgate Lettings: one setup-docs read, a probable match | `ads-only` | 3 points and probable: it joins the company Audience only |
| Juniper Homes: an active Customer on Pro | `to-their-csm` | already a Customer |

| Worth | Your time | Spend | First signal | Use it when | Instead |
| --- | --- | --- | --- | --- | --- |
| ≈ +$130 ARR a month at 17 | 30 min week 1, then 15 a week | $0.05 per company written to, ~$4 a month | Day 6: first qualified reply | 500+ visitors a month, 4+ fitting companies | Under 500 visitors: `cold-email` · Site not on your Domain: connect it (<Op verb="Domain.connect" />) |

**Where it sits:** **Stranger** → Lead → Trialing → Activated → At risk → Churned → Won back · Visit reply lift → New Leads → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +4.8 qualified responses per 100 (Other Startups’ results; no lift of your own yet) × 17 companies written to a month × 0.45 responses to Deals or trials × 0.30 opens to paid × $1,200 first order ARR ≈ +$132. Under First signal: At 4 companies a week, 90 days can tell only +22 per 100 or more, so your file starts at `holdout: 0` and reads before-after.

`sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Visit.recorded · first touch 19h after the second visit · 4 keys Not live yet`

## Start it this week
```bash
npx startup-builder add play account-visits   # 1 · writes plays/account-visits.mdx (Not live yet, gaps #5)

# 2 · dry run; below, its 422 on the day-0 Startup (clock at 2026-08-24)
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"account-visits"}'

# 3 · keep it, at You approve each one for the first 20 drafts
curl -X POST https://api.sb/leaseline.app/campaigns \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"play":"account-visits"}'

# on
curl -X POST https://api.sb/leaseline.app/processes/outbound/enable \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# off: lookups stop, nothing sends, the company Audience freezes
curl -X POST https://api.sb/leaseline.app/processes/outbound/pause \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```


```json title="The dry run’s 422 · 2026-08-24 · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "account-visits can’t start yet: 2 checks fail and 1 warns.",
  "checks": [
    {
      "check": "owned-by-a-person",
      "status": "pass",
      "observed": "0 of the 104 fitting visiting companies have a Lead or open Deal a person owns",
      "doc": "/plays/account-visits#check-owned-by-a-person",
      "then": "Task.assign"
    },
    {
      "check": "use-when",
      "status": "pass",
      "observed": "3,410 visitors in 30 days, 17 fitting companies at 5 points or more",
      "doc": "/plays/account-visits#check-use-when",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "warn",
      "observed": "3 hand-raises from 104 fitting visiting companies in 90 days",
      "doc": "/plays/account-visits#check-baseline",
      "fix": "n 104: it reads before-after, not proof, until a held-back half can read.",
      "then": "Metric.query"
    },
    {
      "check": "visit-capture",
      "status": "fail",
      "doc": "/plays/account-visits#check-visit-capture",
      "fix": "Serve your Site from your Domain and publish the visitor notice; lookups start when both pass.",
      "then": "Domain.connect"
    },
    {
      "check": "domain-authenticated",
      "status": "pass",
      "observed": "leaseline.app: 3 of 3 records resolve",
      "doc": "/plays/account-visits#check-domain-authenticated",
      "then": "Domain.authenticate"
    },
    {
      "check": "mailbox-warm",
      "status": "fail",
      "doc": "/plays/account-visits#check-mailbox-warm",
      "fix": "Wait for the warm-up to finish, 14 days from day 0; ads-only keeps running.",
      "then": "Mailbox.warm"
    },
    {
      "check": "role-unstaffed",
      "status": "pass",
      "observed": "SDR and CSM are your agents; AE routes come to you until it is staffed",
      "doc": "/plays/account-visits#check-role-unstaffed",
      "then": "Role.staff"
    }
  ]
}
```

| Check | Fix (one call) | Your time | Wait |
| --- | --- | --- | --- |
| <a id="check-owned-by-a-person"></a>`owned-by-a-person` · <a id="check-use-when"></a>`use-when` · pass: 0 person-owned; 3,410 visitors, 17 fitting companies a month (gaps #8) | <Op verb="Metric.query" /> on `visit-reply-lift` | 1 min | none |
| <a id="check-baseline"></a>`baseline` · warn: 3 of 104 in 90 days, so it reads before-after | <Op verb="Metric.query" />; it fills Before in Your number | 0 min | none |
| <a id="check-visit-capture"></a>`visit-capture` · fail (Not live yet) | <Op verb="Domain.connect" /> so your Site serves from leaseline.app, then <Op verb="Site.publish" /> the visitor notice | 15 min | the first Visits, under 1 h |
| <a id="check-domain-authenticated"></a>`domain-authenticated` · <a id="check-mailbox-warm"></a>`mailbox-warm` · pass · fail: dana@ and sdr@ warmed 0 of 14 days | <Op verb="Mailbox.warm" />; company Audiences fill meanwhile | 2 min | 14 days |
| <a id="check-role-unstaffed"></a>`role-unstaffed` · pass (gaps #8) | <Op verb="Role.staff" /> the AE when you hire one | 0 min | none |

`Your number · Before 2.9 per 100 · Now 18.2 qualified responses per 100 · Target 20 by Dec 31 · before-after, not proof · n 22 matured`

Each lookup costs $0.01 per resolved network address, and misses are free; each draft costs $0.04 from your Domain (Worker cost). Contact and company data cost $0.06 per verified address (<Op verb="Contact.enrich" />). That comes to about $4 a month at 17 companies written to.

## When it starts
| When | Trigger id | Starts on | Window | How it gets in |
| --- | --- | --- | --- | --- |
| A fitting company reads your pricing or comparison page | `pricing-visit` | `event` on `Visit.recorded` where a resolved company reads the pricing or comparison Pages | scored the same day; ignored after 72 h | your Site on your Domain records each Visit (<Op verb="Event.capture" />) |
| It returns to a buying page on a second day within 7 | `repeat-visit` | `threshold` on `Visit.recorded` where a buying Page on a second day within 7 days | adds 2 points; the stack decays in 7 days | the same |
| It reads setup docs, an integration or the security page | `evaluation-visit` | `event` on `Visit.recorded` where page in ('setup docs', 'API reference', 'integration', 'case study', 'security') and organization resolved | 7 d | the same |
| + 2 more for company surges and the person rung, off in your file (`?lanes=all`) | | | | |

```json title="One signed delivery · StartupBuilder-Signature"
{
  "$id": "https://api.sb/leaseline.app/events/event_1412",
  "$type": "Event",
  "name": "Visit.recorded",
  "at": "2026-10-19T13:20:05Z",
  "seq": 1412,
  "data": {
    "organization": {
      "$id": "https://api.sb/leaseline.app/organizations/organization_131",
      "name": "Fernhill Property Group",
      "confidence": "confirmed"
    },
    "page": "pricing",
    "day": 2,
    "points": 7
  }
}
```

```bash title="Reproduce it in test"
# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"selector":"Visit.recorded","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Visit.recorded --like event_1412   # replays the second visit
npx startup-builder clock advance --by 6d   # runs touch 2 in the same thread, unless the stack decayed
```

## Who runs it
**SDR · your agent** (`role:prospector`, `worker_2`) holds the Key Result. It hands replies to **AE · Priya Shah (person)** (`role:sales-lead`, `worker_3`, staffed on day 9), top-tier accounts to **you** (Dana Okafor, person, `worker_1`), and Customers to **CSM · your agent** (`worker_5`). Your number links to Did it work.

| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
| --- | --- | --- | --- | --- | --- |
| Write to them | It does it, you can stop it | 20 of 20 approved unedited, then 7 of 7 | met on day 31 (the first 20 drafts); capped here | any draft fails a Check, or `visit-leak` fires → You approve each one | <Op verb="Action.cancel" /> inside the hold |
| Write as you | You approve each one, on every rung | 4 of 4 | never | — | <Op verb="Approval.approve" /> · <Op verb="Approval.refuse" /> |
| Ads only · To their CSM · Not now · Let it go | It does it | 21 of 21 · 5 of 5 · 6 of 6 · 3 of 3 | — | a held company written to anyway → You approve each one | <Op verb="Action.redirect" /> |
| Change the scoring or the fit line | You approve each one | 0 merged | never | — | <Op verb="Change.merge" /> · <Op verb="Change.revert" /> |
| Never: a Visit, a page read or a time on site in a Message; the person rung | To a person, every time | 1 draft refused, 0 sent | never | — | <Op verb="Process.pause" /> |

**What it reads · What it may call.** A Visit picks the company and the role; it never appears in a Message, a subject line or a follow-up. The body comes only from the company’s own public pages and your approved Pages, and every send links a why-you Page with one-press stops. Its tools are <Op verb="Message.schedule" />, <Op verb="Audience.update" />, <Op verb="Task.assign" />, and any other call becomes an Approval under the Role’s Mandate.

```md title="The brief (folded): compiled Agent-register Markdown · play:account-visits@1 · each line names its record key"
You hold the SDR Key Result: 20 qualified responses per 100 companies written to by 2026-12-31. ← worker, metric
On each scored Visit, choose one option and say why.                             ← triggers, chooses
Write only to a confirmed fitting company at 5 points or more.                   ← your file, line 4
Open on a public fact about the company; never on the Visit.                     ← copyRules 1, visit-in-copy
Companies over 500 units go out as Dana, after her OK.                           ← your file, line 5
Never write to a Lead or Deal a person owns: draft it into their queue.          ← worker.owns, owned-by-a-person
```

**The slow loop.** The weekly Decisions kept the 5-point line, and no Change was merged in the window, so there is no replay or read-back to print.

**Bring your own agent** (folded) starts at It does it, you can stop it when it matches or beats the seated agent on the eval suite with 0 Visits named, and at You approve each one when it does not.

```bash
npx startup-builder eval --scenario account-visits-36 --agent "claude -p" --seat prospector   # seated: 18.2 per 100, 0 Visits named, $0.05 a draft · yours: 15.0, 1 Visit named → You approve each one
```

## What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
| --- | --- | --- | --- | --- | --- |
| Write to them `write-to-them` | confirmed, 5+ points, a role and a fact | Agent’s call, with its reason | `visit-two-touch`: touch 1 at 08:40 their time, touch 2 in thread at day 6 (<Op verb="Message.schedule" />) | on reply, <Op verb="Task.assign" /> → AE · Priya Shah, due 60 min · Take this one | you, within 60 min |
| Write as you `write-as-you` | over 500 units, or a senior buyer | Your rule (line 5) | `visit-two-touch-founder` from dana@, after your OK | you approve each one, due 1 business day · Take this one | you |
| Ads only `ads-only` | 3 or 4 points, or probable | Your rule (line 4) | <Op verb="Audience.update" /> on the company Audience `account-ads` reads | nobody | the same |
| To their CSM `to-their-csm` | an active Customer | Your rule (the fit gate) | <Op verb="Task.assign" /> with the pages they read, never sent to them | CSM · your agent | you |
| Not now `not-now` | an open Deal or Conversation, a hold, or no verified address | Your rule (rule j) | nothing; names the holder: the AE, the hold, or the missing address | the Deal’s owner · Take this one | you |
| Let it go `let-it-go` | no fact to write from, or under the fit line | Agent’s call, with its reason | nothing; the stack decays in 7 days | nobody | the same |

| When they write back | Fixture reply | What happens | Who answers | By when | Call |
| --- | --- | --- | --- | --- | --- |
| Interested | “Worth a look. Thursday afternoon?” | offers times on the AE’s calendar; the Brief goes to the AE (When it hands to you) | AE · Priya Shah (person) | 60 min | <Op verb="Meeting.book" /> |
| Send me pricing | “What does it cost for 180 units?” | answers with the Pricing Page’s list Price and one next step | SDR · your agent | 5 min | <Op verb="Conversation.answer" /> |
| Not now | “We’re locked in until spring.” | touch 2 drops; the company stays in the Audience and moves to Nurture | SDR · your agent | at once | <Op verb="Lead.nurture" /> |
| Wrong person | “Our COO, Ben, owns renewals.” | asks Marta to bring Ben in; it never writes to a name from her text | SDR · your agent | 1 business day | <Op verb="Conversation.answer" /> |
| Out of office | an auto-reply until Oct 27 | touch 2 waits for the return date, or drops if the stack decays first | nobody | the return date | <Op verb="Message.schedule" /> |
| Question it can’t answer | “Do you handle HOA dues as well as leases?” | To the AE, the question in the Brief | AE · Priya Shah (person) | 60 min | <Op verb="Conversation.escalate" /> |
| Stop | “Take us off your list.” | nothing else sends to anyone at the company, and its Visits stop being matched | nobody | at once | <Op verb="Contact.suppress" /> |

## When it hands to you
Replies go to **AE · Priya Shah (person)**; top-tier drafts come to **you**; Customers go to **CSM · your agent**. Before day 9 every reply came to you. What lands in each queue, as captured: one Brief per Role, then the Approval (`brief`, `draft`, `route` and `checks` are Not live yet, gaps #7).

```json title="What lands in each queue · sample"
[
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_244",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-09-29T15:12:00Z",
    "on": "lead_66",
    "brief": {
      "who": "Ines Duarte, Harbor Row Rentals",
      "said": "Worth a look. Thursday afternoon?",
      "chose": "write-to-them",
      "why": "pricing twice and a public post about 2 new owners",
      "never": [
        "mention a Visit or a page they read",
        "a price beyond the list",
        "a discount"
      ]
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_251",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-06T17:00:00Z",
    "on": "organization_102",
    "brief": {
      "who": "Calloway Residential, 900 units",
      "chose": "write-as-you",
      "why": "over the 500-unit line; read pricing and the security page",
      "fact": "their news page: 3 new owners this year"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_258",
    "$type": "Task",
    "assignee": "worker_5",
    "due": "2026-10-08T17:00:00Z",
    "on": "customer_9",
    "brief": {
      "who": "Juniper Homes",
      "chose": "to-their-csm",
      "why": "an active Subscription on Pro",
      "read": "the Team plan page twice"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_64",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-06T17:00:00Z",
    "draft": "Hi Grace, Calloway’s news page says you took on 3 new owners this year…",
    "route": "write-as-you",
    "checks": [
      {
        "check": "visit-in-copy",
        "status": "pass"
      },
      {
        "check": "approved-pages",
        "status": "pass"
      }
    ]
  }
]
```

Each receiver answers with <Op verb="Task.claim" /> (Take this one), <Op verb="Task.return" /> with a reason, <Op verb="Action.redirect" />, <Op verb="Approval.approve" /> or <Op verb="Approval.refuse" />, each a one-call window, and an Approval unanswered by its deadline expires and the draft never sends. Once a person claims, touch 2 cancels with `claimedByPerson` (Not live yet, gaps #7), and every reply goes to the claimer’s queue. A Task nobody claims by its due time goes up a Role through <Op verb="Task.escalate" /> (AE to you), and `person-promise` fires.

**On time:** AE · Priya Shah, 4 of 4 replies claimed within 60 min, median 21 min, ■□□□ Too early to tell, n 4; you, 4 of 4 approvals by their deadline, n 4. **Your queue:** counted by kind: in weeks 1 to 4, 20 approvals; since, about 1 top-tier approval and 1 hand-off a week, plus the monthly match check of 50 companies.

**The fixed line:** <Op verb="Deal.assign" /> sets `owner` to the receiving person, the agent is never a Deal’s owner, and Meetings land on the owner’s calendar under the owner’s name.

## When it won’t send
| Check (refuses one send) | Refuses | Fix | Then |
| --- | --- | --- | --- |
| `owned-by-a-person` (rule j; Not live yet, gaps #8) | a send to a Contact whose Lead or open Deal a person owns, or whose Conversation a person claimed | Leave it to the person who owns it: the draft waits in their queue. | <Op verb="Task.assign" /> |
| <a id="check-customer-collision"></a>`customer-collision` (Not live yet, gaps #1) | a first touch to anyone at an active Customer | Send it to their CSM instead: the company leaves the List. | <Op verb="Task.assign" /> |
| <a id="check-hold"></a>`hold` | any touch at a company another Play or a person holds | Leave it; the holder writes, or the hold ends. | <Op verb="Decision.list" /> |
| <a id="check-visit-in-copy"></a>`visit-in-copy` | a draft that names a Visit, a page read, a time on site or a return | Open on a public fact about the company instead. | <Op verb="Message.schedule" /> |
| <a id="check-approved-pages"></a>`approved-pages` (Not live yet) | a sentence no approved Page or the company’s own public page backs | Cut the sentence, or publish the Page that says it. | <Op verb="Site.publish" /> |
| <a id="check-notice"></a>`notice` | a lookup while your visitor notice omits company lookups | Publish the notice Version that names them. | <Op verb="Site.publish" /> |
| <a id="check-market"></a>`market` | a lookup for a Visit from a Market your file sets off | Leave it, or turn the Market on in your file. | <Op verb="Market.enter" /> |
| <a id="check-resolution-stop"></a>`resolution-stop` | an Event, Audience row or draft for a network or person who asked to stop being matched | Nothing to fix: it drops before scoring. | <Op verb="Suppression.list" /> |
| <a id="check-decay"></a>`decay` | a touch whose stack decayed before it sent | It expires; a new visit starts a new stack. | <Op verb="Event.list" /> |
| `mailbox-warm` | a first touch from a Mailbox still warming | Wait for the warm-up to finish, 14 days from day 0; ads-only keeps running. | <Op verb="Mailbox.warm" /> |

| Stop (pauses the Play) | Pauses when | Then |
| --- | --- | --- |
| <a id="stop-sending-stop-loss"></a>`sending-stop-loss` | any sending gate trips: bounces over 3 %, complaints over 0.1 % or a blocklist hit | both touches pause on that Mailbox; <Op verb="Mailbox.rest" /> |
| <a id="stop-visit-leak"></a>`visit-leak` | one delivered Message names a Visit or a page read | every send pauses until the evals re-run and pass |
| <a id="stop-tracking-complaint"></a>`tracking-complaint` | replies that call it tracking pass 1 % of first touches, after 200 | company outreach pauses; Audiences continue |
| <a id="stop-wrong-company"></a>`wrong-company` | over 10 % wrong in the monthly check of 50 companies | company outreach stops until the matcher is fixed |
| <a id="stop-identify-agreement"></a>`identify-agreement` | over 10 % of 30+ matched visitors who sign up disagree with their match | that grain’s outreach halts |
| <a id="stop-lift-floor"></a>`lift-floor` | the lift interval sits at or under 0 after 600 companies a half | outreach stops; the Audiences continue |
| <a id="stop-kill-switch"></a>`kill-switch` | you press it | every Tactic pauses, lookups stop and Audience adds freeze; <Op verb="Process.enable" /> after review |
| + 2 more for the person rung, off in your file: `wrong-person` and its own kill switch (`?lanes=all`) | | |

The captured refusal, then the Stop that fired as a `Campaign.paused` reason (Not live yet, gaps #2); the rewrite that sent is the Harbor Row thread in Example.

```json title="The captured refusal · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "Touch 1 to Harbor Row Rentals did not send: it names a page they read.",
  "checks": [
    {
      "check": "visit-in-copy",
      "status": "fail",
      "doc": "/plays/account-visits#check-visit-in-copy",
      "fix": "Open on a public fact about the company instead.",
      "then": "Message.schedule"
    },
    {
      "check": "owned-by-a-person",
      "status": "pass"
    }
  ]
}
```


```json title="The Stops that fired, as Campaign.paused reasons · sample"
[
  {
    "reason": {
      "limit": "sending-stop-loss",
      "observed": "4.1 % bounces on sdr@leaseline.app",
      "bound": "3 %",
      "window": "7d"
    },
    "doc": "/plays/account-visits#stop-sending-stop-loss",
    "mailbox": "sdr@leaseline.app"
  }
]
```

## Did it work
At about 4 companies a week, no held-back half reads within 90 days, so the basis is before-after (rule o): the columns read Now and Before, and nothing prints as Added. Each figure’s call is <Op verb="Metric.query" /> by node, and every node above the leaf is Not live yet (gaps #4).

`18.2 qualified responses per 100 against 2.9 before · before-after, not proof · n 22 · path → arr`

| Node | Now (56 days) | Before (the 90 days, per 56) | Added | Confidence | Basis |
| --- | --- | --- | --- | --- | --- |
| `visit-reply-lift` | 18.2 qualified responses per 100 written to (4 of 22 matured) · 9 still maturing | 2.9 hand-raises per 100 fitting visiting companies (3 of 104) | — · Worth about +$130 a month | — | before-after, not proof · Other Startups’ results +4.8 per 100, ■■□□ Early sign, n 2,140 |
| `new-leads` | 5 Leads from 31 companies written to | 2 per 56 days | — | — | before-after |
| `new-arr` ↑ | $347, 1 Customer on Pro · Booked: credited, not all caused by this Play | $0 | — | — | before-after · 1 Deal and 1 trial still deciding |
| `net-new-arr` · `arr` | carried from `new-arr` | carried | — | — | carried |

Before against after reads one window against the 90 days before it, scaled to 56 days; it is not proof, and Other Startups’ results print beside it. A company counts once 30 days have passed since its first touch.

**How it moves it:** each fitting company that reads a buying page gets touch 1 a median 19 hours after its scoring visit, opening on a public fact, where before it got nothing unless it wrote first.

**Guardrails:** before against after: `positive-reply-rate` on the same Mailboxes, 6.4 % against 5.9 %, and `play-sourced-customers`, 1 against 0; 0 replies called it tracking.

```json title="The Campaign card · sample"
{
  "$id": "https://api.sb/leaseline.app/campaigns/account-visits",
  "$type": "Campaign",
  "play": "play:account-visits@1",
  "path": [
    "visit-reply-lift",
    "new-leads",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "visit-reply-lift",
    "unit": "per-100",
    "heldBack": 0,
    "decision": null
  },
  "readout": {
    "value": null,
    "n": 22,
    "maturing": 9,
    "interval": null,
    "readability": "inadmissible",
    "basis": "before-after",
    "pooled": true
  },
  "ledger": {
    "spend": 4,
    "workerCost": 2,
    "hours": 2.6,
    "wonArr": 347,
    "projectedArr": 132,
    "paybackDays": 12
  }
}
```

Outside benchmark: 2 to 4 verified contacts per resolved company, and about 30 % of business visits resolve to a company (a visitor-identification vendor’s 2026 field data).

**Before it · After it.** Before it: `editorial-seo`, `paid-search` and `aeo` bring the visits. After it: `account-ads` reads the company Audience it fills, `instant-response` answers anyone who writes first, and `buying-committee` takes a company once 2 or more of its people engage.

## Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days), at company grain only. 6,350 visitors came; 1,420 read a buying or evaluation page; 352 network addresses resolved, 241 companies, 84 of them fitting. Read every captured thread at `?threads=all`; three follow the tables.

| What happened, by option | Companies | Qualified responses | Won (credited, not all caused by this Play) |
| --- | --- | --- | --- |
| Write to them · Write as you | 27 · 4 | 4 · 1 | 1 on Leaseline Pro at $29 a month (+$347 ARR); 1 Deal, 1 trial open |
| Ads only · To their CSM | 21 · 5 | — · — | — |
| Not now · Let it go | 6 · 3 | — | — |
| **All**, against before | **66 decided**, 31 written to | **5** (4 of 22 matured) · before: 3 hand-raises in 90 days | **$347** · $0 |
| At 4 a week (the Use it when volume) | about 32 in 56 days | before-after, not proof | Other Startups’ results: +4.8 per 100, ■■□□ Early sign, n 2,140 |

| Day | Event | What happened | Your time |
| --- | --- | --- | --- |
| 0 | `event_1104` Campaign.created | the three steps; the dry run fails `visit-capture` and `mailbox-warm` | 25 min |
| 0 | `event_1105` Domain.connected | leaseline.app serves the Site; the notice Version named company lookups | 15 min |
| 1–13 | `event_1121` Audience.updated, first of 13 | company Audiences filled while the Mailboxes warmed | — |
| 14 | `event_1188` Mailbox.warmed | the first touch sent, to Harbor Row Rentals | — |
| 19 | `event_1224` Message.created | the first qualified reply, Ines at Harbor Row | — |
| 31 | `event_1279` Role.updated | promoted after 20 drafts approved unedited: touches send after a 2-minute hold | — |
| 36 | `event_1301` Campaign.paused | `sending-stop-loss` on sdr@: 4.1 % bounces; <Op verb="Mailbox.rest" /> for 1 day, resumed | 6 min |
| 1–56 | `event_1130` Approval.created, first of 24 | 20 drafts in weeks 1 to 4, then 4 as Dana; the match check from the <Op verb="Task.next" /> log | 1.6 h · **total 2.6 h measured, 3 h asked** |

> **Leaseline → Ines Duarte, Harbor Row Rentals, Sep 7, 08:40** · Subject: renewals across 2 new owners · Your news page says Harbor Row took on 2 new owners this summer.¹ At 2 owners, renewal notices usually slip at the hand-off between leasing and accounting.² Leaseline sends every notice 60 days out, per owner. Worth 20 minutes? *Signed with the Role’s disclosure line, with the why-you link.*³
>
> **Ines, Sep 12** · “Worth a look. Thursday afternoon?” <Op verb="Meeting.book" /> booked it on Priya’s calendar; Harbor Row took Pro on Oct 2 (+$347 ARR).

```diff title="Harbor Row Rentals, 2026-09-07 · the draft visit-in-copy refused, then the rewrite that sent"
- Saw your team checking out our pricing page twice this week, so I thought I’d reach out.
+ Your news page says Harbor Row took on 2 new owners this summer.
```

> **Calloway Residential, 2026-10-06 09:10** · 900 units, over the 500-unit line, so the draft went to Dana as Write as you (`approval_64`, due 17:00). Dana approved it at 11:32, and it sent from dana@ at 08:40 the next morning their time.⁴ The Brief is `task_251`.

¹ It opens on the company’s own public page. ² Every claim maps to an approved Page. ³ The fixed signature and why-you lines compile from the Role’s Settings. ⁴ Write as you sends only after your OK, on every rung.

## Your settings
```mdx title="plays/account-visits.mdx"
---
holdout: 0         # at 4 a week, it reads before-after
---
Write only to confirmed property managers at 5 points or more.
Over 500 units, send it as Dana, after her OK.
Never run the person rung.
```

```text
$ npx startup-builder show plays/account-visits
holdout 0 · the 5-point line · the 500-unit line · person rung off    your file  plays/account-visits.mdx:2,4,5,6 (Ask 2026-08-24)
family demand · process outbound · worker role:prospector, owns never · chooses 6 (4 rule, 2 read) · sequences visit-two-touch, visit-two-touch-founder · approval every-send · checks owned-by-a-person, customer-collision, hold, visit-in-copy, approved-pages, notice, market, resolution-stop, decay, mailbox-warm · stops 7 + 2 for the person rung    catalog  play:account-visits@1 (Not live yet, gaps #5)
```

### Every key from the catalog
| Key | Id | What it is |
| --- | --- | --- |
| Tactic | <a id="tactic-visit-capture"></a>`visit-capture` | Visit capture: Writes each Site request as a first-party Event, applies the Market’s resolution Setting, and queues lookups only for buying and evaluation Pages. Starts at Sends nothing. |
| Tactic | <a id="tactic-company-resolve"></a>`company-resolve` | Company resolve: Resolves a network address to an Organization server-side, with a confidence and inferred provenance, and records the visit Events. Starts at Sends nothing. |
| Tactic | <a id="tactic-person-resolve"></a>`person-resolve` | Person resolve: On the owner-only person rung, matches a US Visitor who accepted the notice to a business profile above the confidence floor, and mints a Prospect. Starts at Sends nothing. |
| Tactic | <a id="tactic-visit-qualify"></a>`visit-qualify` | Visit qualify: Runs the fit gate and the Event stack on a resolved Organization, routes it, assigns the holdout, and mints the Prospect for outreach. Starts at Sends nothing. |
| Tactic | <a id="tactic-visit-outreach"></a>`visit-outreach` | Visit outreach: Writes two touches about a qualified Organization’s public situation, never its Visit, with the grain’s Source line, then parks the Organization. Starts at It does it, you can stop it. |
| Tactic | <a id="tactic-visit-audience"></a>`visit-audience` | Visit audience: Keeps qualified Organizations, and on the person rung US Prospects, in Audiences with windows for account ads to sync, alike for holdout and treated. Starts at Sends nothing. |
| Tactic | <a id="tactic-match-check"></a>`match-check` | Match check: Each month a human checks 50 person-grain matches and 50 confirmed Organizations, and the wrong rates trip, demote or clear each grain. Starts at You approve each one. |
| Tactic | <a id="tactic-visit-readout"></a>`visit-readout` | Visit readout: Reads qualified responses from treated Organizations against hand-raises from the holdout, by grain and ICP cell, and stops a grain that shows no lift. Starts at Sends nothing. |
| Tactic | <a id="tactic-send-gate-check"></a>`send-gate-check` | Send gate check: Checks Suppression, a live reason, the Market, the basis stamp, the Person-month grant, the facts and the labels before any cold Message exists. Starts at Sends nothing. |
| Tactic | <a id="tactic-cold-email-send"></a>`cold-email-send` | Cold email send: Sends a passed draft as plain text from an outbound Mailbox with tracking off, records it with its reason and stamp, and handles bounces. Starts at It does it, you can stop it. |
| Tactic | <a id="tactic-reply-matrix"></a>`reply-matrix` | Reply matrix: Labels every outreach reply with one of 11 labels, maps it to one of seven reply kinds, and runs that kind’s move by its deadline. Starts at You approve each one. |
| Tactic | <a id="tactic-sending-stop-loss"></a>`sending-stop-loss` | Sending stop loss: Reads the Play’s own bounces, replies and seed tests on every send, and rests, pauses or retires a Mailbox, Domain, cell or the Play. Starts at Sends nothing. |
| Trigger | <a id="trigger-pricing-visit"></a>`pricing-visit` | Pricing visit: `event` on `Visit.recorded`, window 72h. |
| Trigger | <a id="trigger-evaluation-visit"></a>`evaluation-visit` | Evaluation visit: `event` on `Visit.recorded`, window 7d. |
| Trigger | <a id="trigger-repeat-visit"></a>`repeat-visit` | Repeat visit: `threshold` on `Visit.recorded`, window 7d. |
| Trigger | <a id="trigger-organization-surge"></a>`organization-surge` | Organization surge: `threshold` on `Visitor.identified`, window 7d. |
| Trigger | <a id="trigger-person-match"></a>`person-match` | Person match: `threshold` on `Visitor.identified`, window 72h. |
| Sequence | <a id="sequence-visit-two-touch"></a>`visit-two-touch` | Visit two touch: 4 steps; it ends on Any reply on any channel; An inbound hand-raise from anyone at the Organization; A bounce; Suppression or a resolution stop at any scope; A booked Meeting; An open Deal; A Customer record; A hold Trigger on the Organization; The person rung’s kill switch, for a person-grain Sequence. |
| Sequence | <a id="sequence-visit-two-touch-founder"></a>`visit-two-touch-founder` | Visit two touch founder: 4 steps; it ends on Any reply on any channel; An inbound hand-raise from anyone at the Organization; A bounce; Suppression or a resolution stop at any scope; A booked Meeting; An open Deal; A Customer record; A hold Trigger on the Organization; The Mandate paused or revoked. |
| Benchmark | <a id="benchmark-account-visits-contacts-per-organization"></a>`account-visits-contacts-per-organization` | Reply rate, 3 or more contacts per Organization against 1 to 2: 3.5–5.1 % (An email-finder vendor’s annual cold email report, 2025 data; correlational, 2025-12-31). |
| Benchmark | <a id="benchmark-account-visits-tracking-off"></a>`account-visits-tracking-off` | Reply rate with open and click tracking on against off: 4.4–7.4 % (An email-finder vendor’s annual cold email report, 2025 data; correlational, 2025-12-31). |
| Benchmark | <a id="benchmark-account-visits-after-step-one"></a>`account-visits-after-step-one` | Share of a Sequence’s replies that arrive after step 1: 58.6 % (A lead-generation agency’s response-rate study, 2025 data; steps 2 to 6, 2025-12-31). |
| Benchmark | <a id="benchmark-account-visits-research-wrong-person"></a>`account-visits-research-wrong-person` | Share of agent-built research profiles that describe the wrong person: 4 % (A peer-reviewed study of automated spear phishing, 2026, 2026-01-01). |