← back to Rentv 2026
PR intel: paginate linkedin-enrich target pool (Cody cycle 3)
e8fc556f55827c6420b07f4dc00a2997eb23ca1b · 2026-08-05 16:26:08 -0700 · Steve
A MAX>500 request silently stalled at 500 targets (the /people API caps a page
at 500), so the broker-first overnight run for 1100 only fetched 500. Paginate
+ dedupe by id until we have MAX*2 candidates to sort + slice. Applies to the
NEXT run; does not touch the live process. Broker-first hit-rate confirmed ~100%
(vs 11% on the media/obscure tail) — targeting, not data, was the limiter.
Files touched
M src/pr/tools/linkedin-enrich.js
Diff
commit e8fc556f55827c6420b07f4dc00a2997eb23ca1b
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Aug 5 16:26:08 2026 -0700
PR intel: paginate linkedin-enrich target pool (Cody cycle 3)
A MAX>500 request silently stalled at 500 targets (the /people API caps a page
at 500), so the broker-first overnight run for 1100 only fetched 500. Paginate
+ dedupe by id until we have MAX*2 candidates to sort + slice. Applies to the
NEXT run; does not touch the live process. Broker-first hit-rate confirmed ~100%
(vs 11% on the media/obscure tail) — targeting, not data, was the limiter.
---
src/pr/tools/linkedin-enrich.js | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/pr/tools/linkedin-enrich.js b/src/pr/tools/linkedin-enrich.js
index aa328db7..ed40b1c1 100644
--- a/src/pr/tools/linkedin-enrich.js
+++ b/src/pr/tools/linkedin-enrich.js
@@ -64,8 +64,16 @@ async function main() {
// Optional targeting: LI_DEPT=agency points enrichment at broker/agent contacts (clear firm
// name → high public-LinkedIn hit-rate) instead of the top-priority pool (bank/obscure = misses).
const deptQ = process.env.LI_DEPT ? `&department=${encodeURIComponent(process.env.LI_DEPT)}` : '';
- const pool = (await api(`/people?linkedin_status=none${deptQ}&limit=${Math.max(MAX * 4, 300)}`));
- let targets = (pool.rows || pool.people || []);
+ // The /people API caps a page at 500, so a MAX>500 request silently stalled at 500
+ // targets (Cody, cycle 3). Paginate + dedupe until we have enough to sort + slice MAX.
+ const want = Math.max(MAX * 2, 300);
+ const seenIds = new Set(); let targets = [];
+ for (let off = 0; targets.length < want; off += 500) {
+ const page = await api(`/people?linkedin_status=none${deptQ}&limit=500&offset=${off}`);
+ const rows = page.rows || page.people || [];
+ for (const p of rows) if (!seenIds.has(p.id)) { seenIds.add(p.id); targets.push(p); }
+ if (rows.length < 500) break;
+ }
if (process.env.LI_MEDIA_ONLY) targets = targets.filter((p) => mediaIds.has(p.organization_id));
// Default: media/PR contacts first (they're the outreach priority). LI_BROKERS_FIRST=1
// flips it — non-media (broker/agent) contacts have a clear firm name so their public
← 39587e39 org drawer: surface each contact's LinkedIn as a clickable �
·
back to Rentv 2026
·
Audience: CRM contacts now surface their REAL enriched Linke 49947825 →