← back to NationalPaperHangers
outreach/IG_DM_PLAYBOOK.md
92 lines
# IG DM Playbook — Operator Guide
One page. Read it once before the first batch.
## (a) Why IG DM (and not cold email) for the paid-ad cohort
The dream-team-fast panel ruled this is the right channel for studios already running paid ads (Google / Meta / Pinterest / TikTok / etc.). Why:
- **Legally clean.** IG DM is a business channel, not commercial email. Zero CAN-SPAM / §17529.5 exposure, no MAILING_ADDRESS requirement in the body, no unsubscribe link required. (We still log the send for audit — see (e).)
- **Higher response rate.** In a small luxury-trade niche, a peer-to-peer DM from Steve's actual IG profile reads as a colleague reaching out, not a vendor blast. Cold email from this cohort reads as spam.
- **Signal of legitimacy.** The recipient sees Steve's IG profile (Designer Wallcoverings + portfolio of work) before they read the message. The DM lands warm.
Email stays as a fallback, but only with explicit per-send authorization — see `scripts/send-claim-invitations.js`.
## (b) How to generate the drafts
```sh
cd ~/Projects/NationalPaperHangers
npm run dm-drafts -- --out=outreach/ig-batch.csv
```
Optional flags:
- `--min=2` — only studios on 2+ paid platforms (tightest cohort)
- `--state=CA` — scope to one state
- `--limit=5` — cap to today's send count
Each row gives you: business_name, ig_handle, city, state, paid_platforms, **dm_message** (paste-ready), claim_url. The dm_message field already ends with the claim URL — copy the whole field, paste, send.
## (c) Cadence
**5 DMs per day, max.** Hard rule.
- More than that and IG starts treating Steve's account as spam (rate-limit, then shadow-ban).
- The luxury trade is small — bursts get noticed and talked about. Slow drip = signal of genuine interest.
- Spread the 5 across morning/afternoon, not all in one minute.
Skip weekends. Trade buyers and studio owners are at projects then.
## (d) When a studio replies
**The claim flow is the funnel — not a sales pitch.** When they reply:
1. Thank them for getting back.
2. Send them their personal claim URL (it's already in the original DM, but resend if they ask).
3. Answer one or two specific questions if they have them — but route them to `/installer/<slug>/claim` for anything beyond that. The page does the heavy lift.
4. If they ask about pricing, the honest answer: Basic is free forever, Pro is $39/mo for the live calendar + Verified badge, Signature is $149/mo for premium placement. No upsell pressure — the listing stays visible regardless of tier.
**Do not** pitch them on Designer Wallcoverings, do not try to upsell, do not mention the WIA badge unless they're a WIA member. The conversation goal is exactly one thing: get them to click the claim URL.
## (e) Logging the send
Every DM gets a row in `comms_send_audit`. The schema is channel-agnostic; `channel='ig_dm'` works fine.
```sql
INSERT INTO comms_send_audit
(channel, campaign, recipient, installer_id, decision, payload)
VALUES
('ig_dm', 'claim_invite', '@<handle>', <installer_id>, 'sent',
'{"dm_text":"<full message>","claim_url":"<url>"}'::jsonb);
```
Or, if you'd rather batch it, save the CSV after sending and run a one-shot loader; the audit row's just for reply tracking and the 7-day follow-up window.
If they ask to be left alone, add the handle to suppression:
```sql
INSERT INTO comms_suppression (channel, identifier, reason, source, installer_id)
VALUES ('ig_dm', '@<handle>', 'optout_reply', 'ig_dm_reply', <installer_id>);
```
The `generate-ig-dm-drafts.js` script does **not** scrub against suppression today (read-only, no DB writes). Before sending, eyeball the CSV against any handles in `comms_suppression WHERE channel='ig_dm'`.
## (f) 7-day follow-up
If no reply at day 7, **one polite nudge — then drop forever.**
```
Hey, following up on this in case it got buried — totally fine to ignore if not for you. Same link if it's useful: <claim_url>
```
If still no reply at day 14, do not message them again. Add a `comms_suppression` row with `reason='no_response_after_followup'` so we don't accidentally re-target them in a future batch.
## Failure-rate watch (Steve's standing rule)
If more than 10% of a batch fails (account locked, message bounced, IG flagged the sends as spam), pause everything and investigate. The DM script itself can't detect this — it's a manual eyeball check on Steve's IG outbox the next morning.
## What this script will NOT do
- Send to IG via the API. Meta TOS forbids unauthorized automation; Steve sends each one by hand.
- Write anything to the DB. The script is read-only.
- Make LLM calls. The DM is template + interpolation.