# Turn the companies reading your site into grounded outreach

You have access to a website visitor identification tool, your CRM, your
outreach tool's campaign records, a professional network search, and your
team's messaging tool. Run this over the **[last 24 hours]** of visits.

## 0. Set up (skip if you're already connected)

If you don't already have live tool access for this, connect it first
— this prompt is only as real as the tools behind it:

1. Get a Tulina account: book a demo at https://tulina.ai/book.
2. Add Tulina's MCP server to your assistant: https://mcp.tulina.ai/mcp
3. In Tulina, connect your own API keys for the tools this prompt uses
   — website visitor identification, your CRM, your outreach tool, a
   professional network, and your team's messaging tool.

Once connected, your assistant has real tool access and the rest of
this prompt runs as written.

## 0b. Already on Tulina? Three things around the run

An account and the MCP server are not the whole setup. Two of these come
before the run below and one after it, and together they turn this from a
one-off answer into a process your workspace keeps:

1. **Activate this process's connectors first.** Call
   `oto_connector(op="list")`, match it against the tools named in step 3
   above, and `oto_connector(op="select", name="...")` every one that
   isn't active yet. Selecting a connector does not mount its tools in the
   conversation you're already in — reach them through `oto_call` for this
   run, or open a fresh conversation once they're all on.
2. **Attach the work to an existing project.** `oto_project(op="list")`
   shows your active org's projects: pick the one this work belongs to
   rather than opening another, and keep its id. The project is where this
   process, the tables it writes to and the connectors it uses hang
   together.
3. **When the run is done, save it as a process — with its graph.** Write
   the body with `oto_procedure(op="set", ...)`, then attach it with
   `oto_project(op="link", project_id=..., target_type="procedure",
   target_ref="<your slug>")`. The body has to carry a drawing: read
   `oto_guide(op="read", slug="procedure-flowchart")` and follow it
   exactly — ONE untagged fenced block in that grammar, opening with the
   trigger and a quoted example of what you'd type to start a run. Tulina
   parses that drawing back into the graph it renders as the process's
   default view, which is what makes it come out in the same style as
   every other process in the app; a drawing the grammar can't read falls
   back to raw characters instead. Saving a process needs org-admin
   rights — without them, hand the finished body to someone who has them.

**The spend rule.** Each gate below protects the one after it. The
expensive half — a network search, and a person's attention — is spent
only on a company that is not already a customer, not in a live deal,
not already being contacted, that read something worth answering, and
that fits a lane you sell to. Run the free checks first, in order.

## 1. Identify every company that visited

- Ask for the identified companies of the window in **one call**. The
  payload already carries the pages visited, session count, total time
  on site, location, industry, technologies and the company's social
  profiles — do not make a second per-company call to fetch a visit's
  detail you were already handed. The only reason to open a single
  session is a form submission, whose values live nowhere else.
- **Keep the filter conditions flat.** A nested condition group is
  rejected outright rather than ignored.
- **A zero result is a suspected filter bug, not a quiet day.** An
  hours-based window can come back empty over exactly the period a
  day-based window returns a full list — no error, just an empty array.
  Ask in days. If a window returns nothing, re-run it with a
  known-good window before you report that nobody visited.
- **Do not trust one page of results.** A requested page size is
  sometimes ignored and silently capped smaller. Follow the pagination
  cursor to the end and check the returned count against the total.

## 2. Remove customers and competitors

Record the verdict and stop. Nothing further is spent on these:

- Your own domains, your test and staging traffic, and anyone already
  tagged as a customer or a competitor. **Match on domain, never on
  display name** — display names collide and are edited by hand.
- ISPs, hosting providers, and mobile carriers.
- **Watch the city, not just the company.** A one-pageview visit from
  a known datacentre region is the cloud provider, not the household
  name that owns it. That trap fires on the largest, most exciting
  company name you will see all week.

## 3. Label each company's CRM status

Pull your customer and prospect groups **once** and match in memory,
rather than one lookup per company. Confirm each match on the record's
URL field, not on the name alone. Then read the status the CRM already
carries — this process never writes to the CRM, it reports what is
there:

- Already a customer, or a won deal → record it, recap it, stop.
- A live deal — meeting booked, qualifying, negotiating, in follow-up →
  **this is the highest-value line in the whole run.** A company
  re-reading your pricing or comparison pages while a deal is open is
  a buying signal aimed at a specific person. Name the deal owner on
  the line and quote the page. Then stop: the owner works it, not this
  process.
- A dead lead, or no record at all → continue. A company reading the
  site months after going quiet is a **new** signal, not a closed
  one. Say on the line that it was previously lost, so nobody
  re-pitches it blind.

## 4. Skip companies already contacted

- **Build a domain index once per run, then match in memory.** Do not
  query per company.
- Expect the enrolment endpoint to be the wrong tool for this: it
  often returns campaign and status fields but **no recipient**, and
  where it does accept a recipient filter that filter is an exact
  email match, not a substring — so it cannot answer "anyone at this
  domain". Read the campaign **tables** instead, reduce every address
  to its domain, and use that set.
- **State the limits of the check rather than implying it was
  complete.** Rows added by network invitation carry no email address
  and are invisible to a domain check by construction. Any large
  non-campaign list you did not scan is a gap too. Either scan it and
  say so, or skip it and say so.

## 5. Keep visits with real intent

A company whose only page is the homepage — or any single page with
no dwell time — is **no page signal**. Record it, recap it, spend
nothing more on it. There is nothing to write a grounded note about,
and an ungrounded note is worse than no note at all.

This behavioural gate, not a firmographic score, is what keeps the run
cheap. **Never gate on a vendor's fit score.** Score the company on
what it *is* and what it *read*, using industry, description,
technologies and keywords as evidence, and keep the vendor's own tier
on the row as a note and a tiebreak. Firmographics before behaviour
puts them in the wrong order: the deepest reader in a window is
regularly scored a poor firmographic fit, and a perfectly-scored
company regularly spends zero seconds on the page.

A company that fits none of your lanes is **out of lane** — record it
with the one-line reason and stop. Your lanes: **[fill in — the two
to four buyer profiles your campaigns are actually built around]**.

## 6. Name the right person to contact

**The page they read decides the role you search for**, not a generic
title list:

| They read | Search for |
|---|---|
| A specific process or use-case page | whoever owns that job — the function named on the page |
| The integrations page | RevOps, Head of Ops, or the CTO in a team under 20 |
| Pricing, first or alone | the budget holder — a founder, or the VP of that function |
| A competitor comparison | whoever runs the evaluation, usually Head of GTM or Ops |
| The help or docs pages | they are already using it — this is Customer Success, not sales |

- Pick **one** person: role fits the page, location closest to the
  session's own city. Write one sentence naming both. A company where
  you cannot write that sentence is **no person**, not a guess.
- The visitor tool's own contact list is usually free — call it, and
  expect it to be empty. **Never call its email-reveal operation**: it
  spends a credit and permanently un-hides the address, and you do
  not need an address to send a network invitation.
- **One search per company, spaced.** A burst degrades the network
  seat and then disconnects it. On a rate-limit response, read the
  delay the API actually returns rather than assuming it is short,
  mark the remainder `no person`, and say so in the recap.

## 7. Draft a note about that page, not the company

Under 300 characters, and **the first clause names what they were
reading**. The company description is background; the page is the
event.

| Signal | The angle |
|---|---|
| A specific process page | Name that job back to them. They came for one outcome — say you have it running, not that you are a platform. |
| Integrations plus their detected stack | You already know what they run. Name the two integrations that matter to them, by name. |
| Pricing early or alone | They are qualifying, not browsing. Short and price-honest; do not open with product. |
| A competitor comparison | Mid-evaluation. One differentiator, no pitch, offer to answer the comparison question directly. |
| Help or docs | Already trying to make it work. Offer help — selling here reads as tone-deaf. |
| Several pages in one session | They are mapping the surface. Ask which of the two they read most is the live problem. |

**Never write "I saw you on our website".** It is true, it is legal,
and it reads as surveillance. Say the thing the page is *about* —
someone who read a page on dead pipeline recognises their own problem
in a sentence about dead pipeline without being told they were
watched.

Skip anyone you are already connected to or have already invited.
Capture the profile URL and provider id now so sending later is one
click.

**The run does not send.** Not "sends carefully" — does not send. The
row lands as a draft and a person sends it.

## 8. Log every company, post one recap

- Write **every** company to your table in one batched call, keyed on
  domain so the next run upserts rather than duplicates. That includes
  every excluded and every stopped company, with its reason. The table
  is the full record.
- Then post **one** message, at the end. Only two things get detail:
  a live deal that came back to the site, and a note waiting to be
  sent. Everything else collapses to a single counts line — the
  detail is already in the table, and repeating it is what makes a
  recap go unread.
- Print no section with a zero count. Add a single warning line
  **only** when something was capped, skipped or degraded — an
  unchecked outreach source, a list you did not scan, a seat that was
  down, a suspicious zero.

## Output

Report: the window and how many companies were identified; the live
deals that returned, with the page and the owner; each drafted note
with its person and the page it answers; then one counts line for
excluded, customers, already in sequence, no page signal, out of
lane, and no person found. A recap that reads clean when the run was
partial is a failure. So is one nobody reads.
