# Write a first-touch email from what they read

**The job:** an opener that references something the person actually did,
written by a model, checked by a human, sent by your normal tooling.

**Who this is for:** anyone whose first-touch reply rate is bad because the
first touch is generic.

**What it costs you:** two API calls per person and a prompt you will rewrite
four times.

---

## Why this works when "personalisation" usually does not

Most personalisation is a merge field. This is different: you know which pages
they read, in order, and how many times they came back. That is a statement
about what they are trying to solve, and it is the only thing worth opening
with.

## Getting the behaviour, not just the person

The REST API gives you the person. For what they read, ask the assistant — it
has the journey tools and will answer in one call:

```bash
curl -s https://app.signal.geysera.com/agent-api/signal/copilot/ask \
  -H "Authorization: Bearer $SIGNAL_COPILOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question": "What pages did dana@acme.com look at, in order, and how many times did she come back?"}'
```

```json
{
  "answer": "Dana Cole visited 7 times between 2 August and 15 September...",
  "question_kind": "descriptive",
  "plan": { "reasoning": "...", "calls": ["visitor_journey"] },
  "disclosures": ["..."],
  "refusal": null,
  "trace": [ { "tool": "visitor_journey", "data": { "...": "..." } } ]
}
```

Two things to note. `answer` is prose for a human; `trace[].data` is the
structured result the prose was written from, and that is what you feed a model
if you want it to reason rather than paraphrase. And `refusal` is not an error
— it is the assistant declining to answer from data it does not have. Check it.

## The prompt

```
You are drafting the FIRST email to someone who has never spoken to us.

What they did on our site:
{journey_json}

What we know about them:
{visitor_json}

Write at most five sentences. Rules:
- Open by referencing one specific thing they read, by name.
- Do not mention that we can see their browsing. Say "I noticed you were
  looking into X" only if X is a topic, never a URL.
- No claim about their company, budget, timeline or intent that is not in the
  data above.
- End with one question that is easy to answer in a sentence.
- If the journey is a single pageview, say you have nothing to personalise on
  and return the word SKIP instead of an email.
```

The SKIP clause is the important one. Roughly a third of identified visitors
have one shallow pageview, and an opener built on that is worse than silence —
it reads as surveillance without insight.

## Keeping a human in the loop

Draft, don't send. Write the drafts somewhere a person clicks approve —
your CRM's task queue, a Slack thread, a spreadsheet. Sending unreviewed
generated mail to people who have not opted in is how a domain gets burned,
and Signal cannot un-send it for you.

## What will go wrong

**The model will invent a pain point.** Every time, unless the prompt forbids
it and you reject drafts that do it. Put the raw journey in the review UI next
to the draft so the reviewer can see the gap.

**Pages tell you less than you think.** A pricing-page visit is not intent to
buy; it is often a competitor or a candidate. `classification` helps —
`competitor` and `excluded` exist for this — but it is not perfect.

**Quiet periods look like churn.** The pixel misses landing pageviews for a
meaningful share of visitors, so "they only read one page" sometimes means "we
only saw one page."

---

Next: [build a daily call list](./build-a-daily-call-list.md) ·
[spot a buying committee](./spot-a-buying-committee.md)
