Arise Enterprise Outreach Outreach Engine
NEEV · 🏛️ Command Center

Outreach Engine

Workflow architecture: scrape → validate → score → draft → human review → send. Validation runs before scoring on purpose — so the priority channel score-leads.mjs picks is a channel proven real, not just a field that happens to be filled in. Every stage is a real, standalone script (Playwright, DNS, local Llama/Ollama, Gemini, Zoho+Gmail SMTP) — not a manual/chat step. Niche-agnostic by design — dental was just the first test scrape; real estate and Chhattisgarh factory/industry scraping followed the same pipeline unchanged. Which niche gets priority is a profile-fit decision, made per campaign. Actual lead counts/results live on a separate scraping-results dashboard, not here.

Proven — live-tested, working Built — blocked on an input Built — blocked on a broken credential Not started Shared / boundary
Lead Discovery — scrape-leads.mjs
120
Max results / city
Google Maps' own real cap — full coverage per city, not a sample.
10+
Fields per lead
Address, phone, website, email, socials, branding language — captured automatically for every lead.
Lead Verification — validate-leads.mjs
5
Channels verified
Email, Website, Instagram, WhatsApp, LinkedIn — each one checked live before it's trusted for outreach.
3
Real techniques
DNS MX lookup + HTTP fetch + Playwright profile-visit — combined, not guessed.
Lead Scoring — score-leads.mjs
6
Signals per lead
Digital Category, Recommended Offer, Channel Count, Priority Channel, SMM flag, Behavior Note — all written automatically.
2,528
Pass ≥60 match
Pass 1: rule-based, free, instant. Pass 2: local Llama 3.1 (Ollama) primary, Gemini (multi-key) → DeepSeek fallback, ICP-fit against a real ICP_PROFILE.md — 2,929/2,951 scored.
Outreach Capacity — draft + send
~2,176
Messages drafted
Real, per-lead-sender messages written — Email/IG/WhatsApp/LinkedIn/Discord. ~178 more flagged for phone (no digital channel).
210
Day-1 send capacity
6 mailboxes (Zoho + Gmail) × 35/day per-mailbox cap. Sending is LIVE (send-email.mjs) — 279 real emails sent all-time, 151 in a single day (21 Aug) across 6 mailboxes in parallel, see send-email.mjs below.
6
Outreach channels
Email → Instagram DM → WhatsApp → LinkedIn → Discord → phone, in priority order.
7
Niches routed
One per mailbox — profile-fit decides which niche gets priority.
_shared/ library baserow-client · zoho-mailer · pdf-gen Lead Discovery — scrape-leads.mjs Playwright → Google Maps → website → Baserow 955 Proven live — any niche/city/country, full-coverage scroll, contact enrichment Lead Verification — validate-leads.mjs Tool: Playwright (IG/LinkedIn/WhatsApp exist-check) + DNS MX lookup + HTTP Proven — 3-lead test passed, now running live across all leads (5,333 and growing) Real script, resumable, checkpoint/resume — WhatsApp-discovers phone-only leads too + separate --backfill-followers mode: fetches IG/LinkedIn follower counts Lead Scoring — score-leads.mjs Pass 1 tool: rule-based JS — no AI, instant, free Proven live — every row: Digital/Non-Digital, channel count, priority channel, SMM flag, behavior note Pass 2 tool: Ollama (local Llama 3.1) primary → Gemini (multi-key rotation) → DeepSeek fallback, vs ICP_PROFILE.md Proven live — 2,929/5,333 scored, 2,528 pass the ≥60 match threshold Message Drafting — draft-outreach.mjs Tool: Claude Haiku (Sonnet escalation) · Email → IG DM → WhatsApp → LinkedIn → Discord Proven live — 2,176+ drafted; migrated 29 Aug off Ollama/Gemini/DeepSeek entirely, same call as job-engine ✓ Mechanical fact-check — numbers, star/review claims, AND invented timeframes cross-verified against real Notes 403 have no digital channel at all — flagged for phone/in-person outreach, not skipped Imran reviews in Baserow ticks "Ready to Send" — always manual Channel — priority order, every lead gets exactly one 1 · Email automated — LIVE, parallel 2 · Instagram automated — not started 3 · WhatsApp draft only — you send it 4 · LinkedIn draft only — you send it 5 · Discord draft only — you send it 6 · Phone no channel found — flagged, not skipped Picked by what scrape-leads.mjs actually found for that lead — Email and Instagram Handle checked first, in order, down to Phone. Email Sender — send-email.mjs Zoho+Gmail · 2/mailbox, parallel, 5-min tick Proven — 279 sent all-time (151 in a single day, 21 Aug), 35/day/mailbox cap IG Sender — ig-cold-dm.mjs Playwright · multi-account · warm-up ramp Not started — no IG account session saved yet (login-setup unrun) ↓ only channels 1 & 2 have an automated sender today Reply Tracking — check-replies.mjs IMAP, 5 mailboxes → replies + bounces, every 30 min Proven — scheduled (AriseOutreachCheckReplies) outreach-dashboard engine.arisegulf.com/outreach-dashboard Proven live — Docker rebuilt & verified, no regression Table 925 outreach_tracker Curated LinkedIn list Imran/Shabiha/Ada separate lane · no automation
Every stage reads/writes Baserow table 955, each one its own standalone script — none of this is a manual/chat step. Table 925 (the existing curated connects tracker) sits outside this pipeline on purpose — a dashed line, not a data connection. Channel picker shows all 6 options; only Email and Instagram have automated senders today.

Build status — detail

_shared/ librarybaserow-client.mjs · zoho-mailer.mjs · pdf-gen.mjs
Proven
Generalized from job-engine's working code. Used by every stage below.
scrape-leads.mjsPlaywright · Google Maps
Proven
Live-tested with a real multi-city run — works for any niche/city/country, not tied to one vertical. Fixed two real bugs along the way: a false-positive Instagram handle when Maps' "website" link was actually an Instagram URL, and a wrong City value when an address had no postal-code segment. Scroll depth fixed to match Google's real 120-result-per-search cap. Captures City/Area/Country/Website/WhatsApp/Facebook/Twitter/LinkedIn/TikTok/Discord/Branding-Language as their own Baserow fields, not buried in Notes. Per-search timing logged to logs/scrape_timing.json — real per-city/per-niche throughput data builds up here over time. First real lead-volume numbers, by niche and country, live on the separate scraping-results dashboard (not this page).
validate-leads.mjsPlaywright (IG/LinkedIn/WhatsApp) + DNS MX lookup + HTTP (website)
Proven
Real, standalone, resumable script — not a manual/chat check, same category of tool as scrape-leads.mjs. Checks every channel a lead actually has before it's trusted for outreach: email domain has a real MX record, website loads, Instagram/LinkedIn profile exists, WhatsApp number is real. Also tests phone-only leads (a number in Notes but no WhatsApp field) directly on wa.me and backfills the WhatsApp field if it's real. 3-lead test passed clean after fixing a machine-level DNS resolver bug; now running live across every lead (5,333 and growing — real estate, dental, Chhattisgarh factories/industries, and Shabiha's Islamic-brand niche as of 22 Aug) with checkpoint/resume so an interruption never re-does work. A separate --backfill-followers mode fetches Instagram/LinkedIn follower counts for channels already confirmed real — a distinct, later pass, not part of the default run (this is why freshly-scraped rows show a validated Instagram handle but no follower number yet — expected, not a bug). Runs before scoring on purpose — see next row.
score-leads.mjsPass 1: rule-based JS · Pass 2: Ollama (local Llama 3.1) primary → Gemini (multi-key) → DeepSeek fallback
Proven
Two independent passes, both live. Pass 1 (rule-based, no AI, free, instant) proven across every lead scraped so far — writes Digital Category, Recommended Offer, Channel Count, Suggested Channel, SMM Candidate, and a templated Behavior Note. Pass 2 (ICP-fit scoring against a real, filled-in ICP_PROFILE.md) has scored 2,929/5,333 — 2,528 pass the ≥60 match threshold and are ready for drafting. (The gap between scored and total is expected — factories/industries and Shabiha's Islamic-brand leads were only just discovered, 21-22 Aug, and haven't been scored yet.) Local Llama 3.1 (Ollama, free, no quota) is the primary scorer; a 7-key Gemini rotation (one API key per team Gmail account) is the fallback when Ollama is off, then DeepSeek as a last resort. 21 Aug: confirmed both keying off a shared Google Cloud project quota — rotating keys does not multiply daily capacity, only smooths per-minute bursts.
draft-outreach.mjsClaude Haiku + Sonnet escalation · locked message-writing playbook · mechanical fact-check
Proven, migrated 29 Aug
29 Aug: migrated off Ollama/Gemini/DeepSeek entirely — Imran's explicit call, same day and same reason as job-engine's match-jobs.mjs/tailor-and-draft.mjs migration. Now runs on Claude Haiku via the Claude Code CLI (Imran's own subscription, no separate API key), Sonnet as a single escalation retry when a response fails validation. Live-tested on real rows across English, Arabic, and Bilingual-branded leads (the exact risk category a 21 Aug test on this same file flagged for encoding corruption) — clean, no corruption, confirmed directly against Baserow. Real fabrication caught and fixed the same day: a test draft claimed "your 5★ rating" and "takes about a week to set up" — neither was in that lead's real Notes. A worded "don't invent numbers" rule alone didn't stop it (same lesson as job-engine's resume drafting), so the mechanical fact-checker was extended to also catch star/review claims and any implementation-timeframe claim, not just percentages — re-tested clean afterward. ~2,176 qualified leads drafted — real per-lead sender (Imran/Gulfisha/Shabiha, matching the locked outreach-routing table by niche+country; "Ada" retired from outreach entirely, 18 Aug). Always drafted in English regardless of the business's own branding script, except Hindi/Bilingual leads which get native-language copy — the prompt itself now carries this instruction directly, no more language-based provider routing. ~178 have no digital channel at all — flagged in Notes for phone/in-person outreach, not skipped.
send-email.mjsZoho + Gmail SMTP, per-mailbox daily-cap discipline
Proven — live, parallel
Credential issue resolved. 21 Aug rebuilt: caps are now PER MAILBOX (35/day each, not one shared 35/day total — the old shared cap silently blocked a real 60-email day's target), and ready rows are grouped by resolved mailbox and sent CONCURRENTLY (up to 2/mailbox/tick) so two mailboxes never starve each other on row order. Real sender routed by niche+country via outreach-routing.mjs (Imran/Gulfisha/Shabiha only — "Ada" retired 18 Aug, never a real prospect-facing sender). 279 real emails sent all-time (151 in a single day, 21 Aug) across 6 mailboxes (ImranZoho, GulfishaZoho, ContactZoho, ImranGmailNetwork, GulfishaGmail01/02). Scheduled task AriseOutreachSendEmail, every 5 min.
ig-cold-dm.mjsPlaywright, saved-session login, warm-up ramp
Not started
Code complete: multi-account rotation, per-account daily cap with warm-up ramp, human-like typing delay, auto-pause + Telegram alert on any restriction language. Needs ig-login-setup.mjs run once per real IG account before first live send.
check-replies.mjsIMAP, 5 mailboxes (4 Zoho + 1 Gmail), email only
Proven — live, scheduled
21 Aug: wired up real bounce detection — Baserow already had Bounced/Bounce Reason columns that nothing was writing to; bounce DSNs are now matched against sent rows by scanning the bounce body for a known recipient address and flagged, instead of being silently skipped. Added ImranGmailNetwork (arisenetwork.cg@gmail.com) to the watch list — real-estate India sends had zero reply/bounce visibility before this. New scheduled task AriseOutreachCheckReplies, every 30 min (previously only job-engine's copy was scheduled). Instagram DM replies still aren't covered (would need the cold-DM accounts wired into growth-engine's Graph webhook, or manual checks).
outreach-dashboardengine.arisegulf.com/outreach-dashboard
Proven
Static HTML, same visual family as job-dashboard. growth-engine's Docker container rebuilt and restarted to serve it — verified live, no regression on existing routes.