orangeslice 2.1.2 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,11 +15,12 @@ description: Strategies for searching or finding people and companies. This is a
15
15
 
16
16
  Run queries with built-in filters when the criteria is searchable:
17
17
 
18
- - **Web search (`services.web.search`)** — **Default for LinkedIn**. Use for keywords, niche queries, fuzzy matching, anything descriptive.
18
+ - **Web search (`services.web.search`)** — **Default for ALL prospecting**. Use for keywords, niche queries, fuzzy matching, anything descriptive. This includes finding LinkedIn profiles/companies via `site:linkedin.com` queries.
19
19
  - **Crunchbase (`services.crunchbase.search`)** — **Default for funding data**. Use for funding-stage, round type, amount, date windows, and investor-backed company discovery.
20
- - **LinkedIn B2B DB** — **Indexed lookups ONLY:** company by domain/slug/ID, employees at a known company (by company_id), basic funding (2-table join). Everything else = web search. See [QUICK_REF](./linkedin_data/QUICK_REF.md).
20
+ - **Ocean.io (`services.ocean.search.*`)** — **Default for lookalike search**. When the user has example companies/domains and wants to find more like them. See [Lookalike Search Guide](../lookalike-search/).
21
21
  - **Google Maps** — industry, location, ratings
22
22
  - **LinkedIn job search** — job filters, titles
23
+ - **LinkedIn B2B DB** — **Almost never for prospecting.** Acceptable only for trivially simple single-indexed-column filters (e.g. `industry_code = 4 AND country_code = 'US'`), looking up entities you already have an identifier for, or listing employees at a single known company. Any query involving keywords, descriptions, names, skills, or multi-criteria matching = web search. See [QUICK_REF](./linkedin_data/QUICK_REF.md).
23
24
 
24
25
  **Use this when possible.** It's fast and returns pre-filtered results.
25
26
 
@@ -83,11 +84,12 @@ When using qualification columns, think Circle & Star:
83
84
 
84
85
  | Source | Use When | Limitations |
85
86
  | ------------------------ | ----------------------------------------------------------- | -------------------------------------------------------- |
86
- | **Web Search (Default)** | **Everything else** — keywords, niche, fuzzy, specific | Requires verification columns for false positives. |
87
+ | **Web Search (Default)** | **ALL prospecting/discovery** — keywords, niche, fuzzy, specific, LinkedIn profiles & companies via `site:linkedin.com` | Requires verification columns for false positives. |
87
88
  | **Crunchbase (Funding Default)** | Funding-focused prospecting: stage, round type, amount, recency, investors | Best for funding intelligence; use other sources for non-funding discovery criteria. |
89
+ | **Ocean.io (Lookalike Default)** | User has seed domains and wants similar companies/people. "Find companies like X." | Needs seed domains as input. Not for keyword/niche discovery from scratch. See [guide](../lookalike-search/). |
88
90
  | **PredictLeads** | Company intelligence, buying signals, and structured company events at scale | Coverage varies by company/market; use web search for very niche long-tail discovery. |
89
91
  | **Niche Directory Scrape** | Well-defined categories with existing lists (see below) | Requires finding the right directory first. |
90
- | **LinkedIn B2B DB** | **Indexed lookups ONLY:** company by domain/slug/ID, employees at known company, basic 2-table funding. | **3s hard max. No keyword search, no LATERAL, no 3+ table joins.** Everything else = web search. |
92
+ | **LinkedIn B2B DB** | **Almost never for prospecting.** Only for: (1) lookups by known identifier (URL/domain/ID), (2) employees at a single known company, (3) trivially simple single-indexed-column filters like `industry_code` or `country_code`. | **Any query with keywords, descriptions, names, ILIKE, skills, or multi-criteria = web search.** The bar is extremely high — if in doubt, use web search. |
91
93
  | **Google Maps** | Local/SMB, physical locations, restaurants, retail | Limited to businesses with physical presence. |
92
94
  | **Apify Actors** | Platform-specific scraping (Instagram, TikTok, job boards) | Per-platform setup. May break with platform changes. |
93
95
 
@@ -104,13 +106,13 @@ PredictLeads is usually the best choice for:
104
106
  Prefer other sources when:
105
107
  - You need **brand-new niche discovery** with fuzzy intent matching -> use `web.search`
106
108
  - You need local storefront/SMB discovery -> use Google Maps
107
- - You need fast indexed LinkedIn lookups by known IDs/domain/company -> use LinkedIn B2B DB
109
+ - You need to look up a specific company/person by known URL/domain/ID -> use LinkedIn B2B DB (lookup only, NOT discovery)
108
110
 
109
111
  ### Funding Prospecting Standard: Use Crunchbase First
110
112
 
111
113
  For any request centered on funding data (for example: "Series A fintech companies", "companies that raised in the last 12 months", "recently funded startups"), use `services.crunchbase.search` as the **standard/default source**.
112
114
 
113
- Use LinkedIn B2B DB funding joins only when the user explicitly needs a LinkedIn-only workflow or a narrow lookup tied to existing LinkedIn records. Otherwise, Crunchbase should be the first choice for funding-oriented discovery.
115
+ **Never use LinkedIn B2B DB for funding discovery.** Crunchbase is always the right choice for finding funded companies. LinkedIn B2B DB funding tables should only be used when you already have a specific company ID and need to check its funding history.
114
116
 
115
117
  ### Niche Directory Scraping — For Well-Defined Categories
116
118
 
@@ -141,9 +143,12 @@ When users ask for companies in a **specific, well-defined niche** (e.g., "fast
141
143
 
142
144
  ## 🚨 Critical: Web Search vs B2B Database
143
145
 
144
- ### Web Search (`services.web.search`) — DEFAULT CHOICE
146
+ ### Web Search (`services.web.search`) — DEFAULT CHOICE FOR PROSPECTING
145
147
 
146
- **Use web search for everything unless the query is purely industry/title or high volume and willing to sadrifice q**
148
+ **Use web search for almost all prospecting and discovery. The LinkedIn B2B DB should almost never be your first choice.**
149
+
150
+ > **🚫 STOP: Are you about to query the LinkedIn B2B DB to find new leads?**
151
+ > Unless your query is a **trivially simple single-indexed-column filter** (e.g. `industry_code = 4 AND country_code = 'US'`), **use web search instead**. The moment your query involves keywords, descriptions, company names, headlines, skills, ILIKE, or any multi-criteria matching — it's a web search query, not a DB query.
147
152
 
148
153
  Web search handles:
149
154
  - Keywords, product names, technologies ("AI CRM", "Salesforce", "React")
@@ -151,6 +156,7 @@ Web search handles:
151
156
  - Fuzzy matching (anything that's hard to express as exact filters)
152
157
  - Any descriptive criteria (company descriptions, headlines, bios)
153
158
  - Small-to-medium result sets (10-500 results)
159
+ - **Most volume requests** — batched web searches are often better than DB queries even for high volume
154
160
 
155
161
  ```
156
162
  site:linkedin.com/company "AI CRM"
@@ -159,39 +165,46 @@ site:linkedin.com/in "VP Sales" "fintech"
159
165
 
160
166
  Web search is fast, cheap, and works for almost everything. **When in doubt, use web search.**
161
167
 
162
- ### LinkedIn B2B Database — LOOKUP TOOL ONLY
168
+ ### LinkedIn B2B Database — LAST RESORT FOR PROSPECTING
163
169
 
164
- > **The LinkedIn DB is a lookup tool, not a search engine.** Only fast indexed queries are allowed (under 3 seconds, max 2-table joins). Everything else falls back to `services.web.search` with `site:linkedin.com` patterns. **You MUST read `services/web/search` before using web search.**
170
+ > **🚫 The LinkedIn DB is almost never the right tool for prospecting.** It is primarily an enrichment/lookup tool for entities you ALREADY know about. The only prospecting exception is **trivially simple queries on single indexed columns** (e.g. `industry_code`, `country_code`, `company_size_code`, `employee_count`).
165
171
 
166
172
  > **🚨 CRITICAL: ALWAYS SAVE LINKEDIN DB RESULTS TO A FILE 🚨**
167
173
  > LinkedIn B2B database queries are **billed per execution**. You **MUST** persist query results immediately using `fs.writeFile("files/<name>.json", JSON.stringify(rows))`. If you return results without saving them, the query must be re-run — **double-charging the user**. Never discard, summarize-only, or preview LinkedIn DB results without also writing them to a file in the same step.
168
174
 
169
- **ALLOWED queries (all under 3s, max 2-table joins):**
170
- - Company by domain/slug/ID (4-8ms)
171
- - Employees at a known company by company_id (8-32ms)
172
- - Basic funding with 2-table join (10-99ms)
173
- - Certifications (160-312ms)
174
- - Education-only queries (83-257ms)
175
- - Common headline terms ONLY: engineer, CEO, manager, sales, developer, founder (51-161ms)
176
-
177
- **BANNED queries use web search instead:**
178
- - ❌ Description/keyword search (ILIKE on description = 10s)
179
- - ❌ Jobs by role (LATERAL = 28s timeout)
180
- - ❌ 3+ table joins (1s-17s)
181
- - ❌ Skills queries (timeout)
182
- - ❌ Rare headline terms (timeout)
183
- - ❌ UNION ALL for multiple companies (14.6s)
184
- - ❌ company_name ILIKE (813ms-11.7s)
185
-
186
- **Example ALLOWED queries:**
187
- - "Find employees at Stripe" (company_id lookup)
188
- - "Companies with Series A funding" (2-table join)
189
-
190
- **Example BANNED queries use web search:**
175
+ **Acceptable uses of LinkedIn B2B DB:**
176
+ - Look up a specific company by its domain, slug, or ID (you already have the identifier)
177
+ - List employees at a single company you already identified (you have the company_id)
178
+ - Check funding history for a specific company you already identified
179
+ - **Trivially simple prospecting** on a single indexed column: e.g. `WHERE industry_code = 4 AND country_code = 'US' LIMIT 50` — no keywords, no ILIKE, no descriptions, no names
180
+
181
+ **The test: can your query be expressed with ONLY indexed equality/range filters on 1-2 columns?** If yes, LinkedIn DB is OK. If you need keywords, descriptions, ILIKE on names, skills, fuzzy matching, or anything semantic — **use web search**.
182
+
183
+ **❌ BANNED for prospecting (use web search):**
184
+ - ❌ Any query with keywords or descriptions ("AI CRM", "fintech", "climate tech")
185
+ - ❌ Any query with ILIKE on names, headlines, or titles
186
+ - ❌ Any query requiring skills matching
187
+ - ❌ Any query with 3+ table joins
188
+ - ❌ Any query where you're "searching" rather than "filtering by a code"
189
+ - ❌ "Find Series A startups" Crunchbase
190
+ - ❌ "Find VPs at fintech companies" → web search
191
+
192
+ **✅ ALLOWED for prospecting (trivially simple):**
193
+ - "US software companies" `WHERE industry_code = 4 AND country_code = 'US'`
194
+ - "Companies with 100-500 employees in California" `WHERE employee_count BETWEEN 100 AND 500 AND region = 'California'`
195
+
196
+ **✅ ALLOWED (enrichment/lookup of known entities):**
197
+ - "Get details on Stripe" (you have the domain `stripe.com`) → LinkedIn DB lookup
198
+ - "List engineers at Stripe" (you have company_id `2135371`) → LinkedIn DB employees query
199
+ - "What's this person's headline?" (you have their LinkedIn slug) → LinkedIn DB lookup
200
+
201
+ **❌ BANNED (discovery) — use web search:**
191
202
  - "AI CRM companies" → `services.web.search("site:linkedin.com/company AI CRM")`
192
203
  - "Kubernetes engineers" → `services.web.search("site:linkedin.com/in kubernetes engineer")`
193
204
  - "VPs who worked at Google" → `services.web.search("site:linkedin.com/in VP Google")`
194
205
  - "Companies hiring Account Executives" → `services.web.search("site:linkedin.com/jobs Account Executive")`
206
+ - "1000 software engineers in Bay Area" → batched `services.web.search` queries
207
+ - "Healthcare companies that do X" → `services.web.search("site:linkedin.com/company healthcare X")`
195
208
 
196
209
  ## Fast but Requires Verification
197
210
 
@@ -215,7 +228,8 @@ await sheet.addRows(
215
228
  🚨 WEB SEARCH REQUIRES VERIFICATION 🚨
216
229
  When using web search to find companies or people, you MUST add:
217
230
  1. An enrichment column (LinkedIn enrich or scrape)
218
- 2. A verification column (AI check: "Does this actually match the criteria?")
231
+ 2. SPECIFICALLY AI verification columns (AI check: "Does this actually match the criteria?")
232
+ 3. You must use AI for verification
219
233
  NEVER deliver web search results without verification columns. Web search produces false positives.
220
234
 
221
235
  ````
@@ -239,56 +253,52 @@ type search = (params: {
239
253
  }>;
240
254
  ```
241
255
 
242
- ## Create Useful Views After Prospecting
243
-
244
- Once a prospecting workflow is set up, **always create a few views**. Views show up as colored tabs in the sheet bar so switching is instant.
256
+ ## Sort Prospects by Fit
245
257
 
246
- Use `ctx.sql()` with `CREATE VIEW ... ON ... AS SELECT ...`.
247
-
248
- **Prefer sorted views over filtered views.** A sorted view keeps ALL rows visible but groups the best ones at the top — the user sees qualified leads first and can scroll to see the rest. Filtered views hide rows, making it hard to judge how much work went into finding the qualified ones.
258
+ After prospecting, sort the sheet so the best-fit prospects are at the top. Use `SET FILTERS` to apply a sort immediately:
249
259
 
250
260
  ```ts
251
- // Sorted view qualified at top, rest below (preferred)
252
- await ctx.sql(
253
- `CREATE VIEW "Best First" ON "Companies" AS SELECT * FROM "Companies" ORDER BY "Qualified" DESC, "Score" DESC`
254
- );
261
+ await ctx.sql(`SET FILTERS ON "Companies" ORDER BY "Score" DESC`);
262
+ ```
255
263
 
256
- // Sorted by score
257
- await ctx.sql(`CREATE VIEW "By Score" ON "Companies" AS SELECT * FROM "Companies" ORDER BY "Score" DESC`);
264
+ **Sort > filter.** Sorting keeps all rows visible so the user can see how many prospects were disqualified — this makes the work visible. Filtering hides rows and makes it look like nothing happened.
258
265
 
259
- // Grouped by category
260
- await ctx.sql(`CREATE VIEW "By Industry" ON "Companies" AS SELECT * FROM "Companies" ORDER BY "Industry" ASC`);
266
+ Boolean columns work too — `true` sorts after `false` with DESC: `ORDER BY "Qualified" DESC, "In ICP" DESC NULLS LAST`
261
267
 
262
- // Only use WHERE filters for hard exclusions
263
- await ctx.sql(`CREATE VIEW "Errors Only" ON "Companies" AS SELECT * FROM "Companies" WHERE "Status" = 'failed'`);
264
- ```
268
+ Optionally create a saved view if the user would benefit from toggling between perspectives:
265
269
 
266
- Don't overthink it — just create 2-3 views that match the columns you built. Skip only if there's genuinely nothing to sort/group on.
270
+ ```ts
271
+ await ctx.sql(`CREATE VIEW "Best First" ON "Companies" AS SELECT * FROM "Companies" ORDER BY "Score" DESC`);
272
+ ```
267
273
 
268
274
  ## Examples
269
275
 
270
- | User Request | Approach | Why |
271
- | -------------------------------------------- | ---------------- | --------------------------------------------------------------------------- |
272
- | "AI CRM companies" | Web search | Keyword query → `"AI CRM" site:linkedin.com/company` |
273
- | "Fintech startups" | Web search | Fuzzy/descriptive → `"fintech" "startup" site:linkedin.com/company` |
274
- | "SDRs at Series A companies" | Web search | Specific criteria → `"SDR" "Series A" site:linkedin.com/in` |
275
- | "Series A/B companies raised last year" | Crunchbase | Funding-specific discovery is best handled via `services.crunchbase.search` |
276
- | "Companies using Kubernetes" | Web search | Technology match → `"Kubernetes" site:linkedin.com/company` |
277
- | "VPs who worked at Google" | Web search | Fuzzy history match → `"VP" "Google" site:linkedin.com/in` |
278
- | "1000 software engineers in Bay Area" | B2B DB | Simple title + location + high volume |
279
- | "All healthcare companies 100-500 employees" | B2B DB | Industry + size + high volume |
280
- | "Fast food chains that..." | Directory scrape | Scrape Wikipedia list `browser.execute` |
281
- | "Restaurants in Austin" | Google Maps | Local/SMB with physical presence |
282
- | "Companies hiring SDRs" | LinkedIn Jobs | Job search with title filter |
283
- | "Warehouses implementing WMS" | Circle + columns | Pull logistics companiesadd "WMS Score" column |
284
- | "Companies that recently switched CRMs" | Circle + columns | Pull SaaS companies → add "CRM Change Signals" column |
276
+ | User Request | Approach | Why |
277
+ | ------------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------- |
278
+ | "AI CRM companies" | Web search | Keyword query → `"AI CRM" site:linkedin.com/company` |
279
+ | "Fintech startups" | Web search | Fuzzy/descriptive → `"fintech" "startup" site:linkedin.com/company` |
280
+ | "SDRs at Series A companies" | Web search | Specific criteria → `"SDR" "Series A" site:linkedin.com/in` |
281
+ | "Series A/B companies raised last year" | Crunchbase | Funding-specific discovery is best handled via `services.crunchbase.search` |
282
+ | "Companies using Kubernetes" | Web search | Technology match → `"Kubernetes" site:linkedin.com/company` |
283
+ | "VPs who worked at Google" | Web search | Fuzzy history match → `"VP" "Google" site:linkedin.com/in` |
284
+ | "Companies like Stripe and Brex" | Ocean.io | Lookalike search with seed domains `ocean.search.companies` |
285
+ | "Find VPs at companies similar to our customers" | Ocean.io | Lookalike companies + people filters `ocean.search.people` |
286
+ | "1000 software engineers in Bay Area" | Web search | Batched `site:linkedin.com/in "software engineer" "Bay Area"` queries |
287
+ | "US software companies with 100-500 people" | B2B DB | Trivially simple: `industry_code = 4 AND employee_count BETWEEN 100 AND 500` — no keywords/ILIKE needed |
288
+ | "Healthcare companies that use AI" | Web search | Has keywords ("AI") `site:linkedin.com/company "healthcare" "AI"` + enrich |
289
+ | "Fast food chains that..." | Directory scrape | Scrape Wikipedia list`browser.execute` |
290
+ | "Restaurants in Austin" | Google Maps | Local/SMB with physical presence |
291
+ | "Companies hiring SDRs" | LinkedIn Jobs | Job search with title filter |
292
+ | "Warehouses implementing WMS" | Circle + columns | Pull logistics companies → add "WMS Score" column |
293
+ | "Companies that recently switched CRMs" | Circle + columns | Pull SaaS companies → add "CRM Change Signals" column |
285
294
 
286
295
  ---
287
296
 
288
297
  ## Tools
289
298
 
290
- - **LinkedIn:** `services.company.linkedin.search({ sql: "SELECT ... FROM linkedin_company ..." })`, `services.person.linkedin.search({ sql: "SELECT ... FROM linkedin_profile ..." })` **Lookup tool only, 3s max, 2-table joins max. Use web search for anything else.**
299
+ - **LinkedIn DB (LOOKUP + trivially simple filters ONLY):** `services.company.linkedin.search(...)`, `services.person.linkedin.search(...)` **Primarily for enrichment/lookup. Only use for prospecting when the query is a trivially simple indexed-column filter (e.g. industry_code, country_code). Any keywords, ILIKE, descriptions, names, skills = web search.**
291
300
  - **Funding:** `services.crunchbase.search({ sql: "SELECT ... FROM ... WHERE ..." })` — **Default for funding search and screening.**
301
+ - **Lookalike:** `services.ocean.search.companies`, `services.ocean.search.people` — **Default for "find companies like X".** See [Lookalike Search Guide](../lookalike-search/).
292
302
  - **Local/SMB:** `googleMaps.scrape`
293
303
  - **Web:** `web.search` + `browser.execute`
294
304
  - **Platforms:** `services.apify.runActor`
@@ -5,7 +5,9 @@ description: Critical rules and query methodology for LinkedIn B2B database. Man
5
5
 
6
6
  # B2B SQL Reference
7
7
 
8
- > **The LinkedIn DB is a lookup tool, not a search engine.** Only fast indexed queries are allowed (under 3 seconds, max 2-table joins). Everything else falls back to `services.web.search` with `site:linkedin.com` patterns. **You MUST read `services/web/search` before using web search.**
8
+ > **🚫 BEFORE YOU QUERY: Is this for prospecting/discovery?** This database is almost never the right tool for finding new leads. It is primarily for lookups and enrichment of entities you already have identifiers for. The only prospecting exception is **trivially simple queries on single indexed columns** (e.g. `industry_code = 4 AND country_code = 'US'`). Any query with keywords, descriptions, ILIKE on names, skills, or semantic matching → use `services.web.search` with `site:linkedin.com` instead.
9
+
10
+ > Only fast indexed queries are allowed (under 3 seconds, max 2-table joins). Everything else falls back to `services.web.search` with `site:linkedin.com` patterns. **You MUST read `services/web/search` before using web search.**
9
11
 
10
12
  ---
11
13
 
@@ -1,37 +1,58 @@
1
1
  ---
2
2
  name: linkedin_data
3
- description: LinkedIn B2B database — LOOKUP TOOL ONLY. Fast indexed queries under 3s. Everything else uses web search.
3
+ description: LinkedIn B2B database — LOOKUP & ENRICHMENT TOOL. Almost never for prospecting. Only trivially simple indexed-column filters are acceptable for discovery.
4
4
  ---
5
5
 
6
6
  # LinkedIn B2B Database
7
7
 
8
- > **The LinkedIn DB is a lookup tool, not a search engine.** Only fast indexed queries are allowed (under 3 seconds, max 2-table joins). Everything else falls back to `services.web.search` with `site:linkedin.com` patterns. **You MUST read `services/web/search` before using web search.**
8
+ > **🚫 This database is almost never the right choice for prospecting/discovery.** It is primarily a lookup & enrichment tool for entities you already have identifiers for. The only prospecting exception is **trivially simple queries on single indexed columns** (e.g. `industry_code = 4 AND country_code = 'US'`).
9
+ >
10
+ > **Before querying this database, ask yourself:** "Am I searching/discovering, or am I looking up something I already have an ID for?" If searching → use `services.web.search`. If looking up → proceed.
11
+
12
+ ---
13
+
14
+ ## When to Use This Database
15
+
16
+ | Use Case | Example | OK? |
17
+ | -------------------------------- | ---------------------------------------------------------- | ---------------------------------------------- |
18
+ | **Lookup by known identifier** | Company by domain/slug/ID, person by LinkedIn URL | ✅ Always OK |
19
+ | **Employees at a known company** | People at Stripe by company_id | ✅ Always OK |
20
+ | **Trivially simple prospecting** | `WHERE industry_code = 4 AND country_code = 'US' LIMIT 50` | ✅ OK — no keywords, no ILIKE, no descriptions |
21
+ | **Keyword/description search** | "AI CRM companies", "fintech startups" | ❌ Use web search |
22
+ | **Any ILIKE on names/headlines** | `headline ILIKE '%kubernetes%'` | ❌ Use web search |
23
+ | **Skills, rare terms, fuzzy** | "python engineers", "climate tech" | ❌ Use web search |
24
+ | **Multi-criteria discovery** | Industry + funding + keywords | ❌ Use web search + Crunchbase |
25
+
26
+ **The test:** Can your query be expressed with ONLY indexed equality/range filters (industry_code, country_code, company_size_code, employee_count, region)? If yes, LinkedIn DB is acceptable. If you need ANY keywords, descriptions, ILIKE, skills, or semantic matching — **use web search**.
9
27
 
10
28
  ---
11
29
 
12
30
  ## What This Database CAN Do (Under 3s)
13
31
 
14
- | Query Type | Example |
15
- | -------------------------- | ------------------------------------------------- |
16
- | Company by domain/slug/ID | Find Stripe by `stripe.com` |
17
- | Employees at known company | People at Stripe by company_id |
18
- | Basic funding (2-table) | Series A companies |
19
- | Jobs at ONE company | Open roles at Stripe |
20
- | Person by LinkedIn URL | Find person by slug |
21
- | Certifications | AWS certified people |
22
- | Education-only | Stanford graduates |
23
- | Headline (6 common terms) | engineer, CEO, manager, sales, developer, founder |
32
+ | Query Type | Example |
33
+ | ------------------------------------ | ------------------------------------------------- |
34
+ | Company by domain/slug/ID | Find Stripe by `stripe.com` |
35
+ | Employees at known company | People at Stripe by company_id |
36
+ | Simple indexed-column company filter | `industry_code = 4 AND country_code = 'US'` |
37
+ | Basic funding (2-table) | Funding history for a known company |
38
+ | Jobs at ONE company | Open roles at Stripe |
39
+ | Person by LinkedIn URL | Find person by slug |
40
+ | Certifications | AWS certified people |
41
+ | Education-only | Stanford graduates |
42
+ | Headline (6 common terms ONLY) | engineer, CEO, manager, sales, developer, founder |
24
43
 
25
44
  ## What This Database CANNOT Do (Use Web Search)
26
45
 
27
46
  | Query Type | Web Search Alternative |
28
47
  | ------------------------------- | ------------------------------------------ |
29
48
  | Company by keywords/description | `site:linkedin.com/company [keywords]` |
49
+ | Any ILIKE on names/headlines | `site:linkedin.com/in [keywords]` |
30
50
  | Jobs by role across companies | `site:linkedin.com/jobs [role] [location]` |
31
51
  | People by rare headline terms | `site:linkedin.com/in [keywords]` |
32
52
  | People by skills | `site:linkedin.com/in [skill]` |
33
53
  | 3+ table joins | Decompose into 2-table queries |
34
54
  | Complex alumni (ex-X now-Y) | Two separate queries |
55
+ | Any fuzzy/semantic matching | Web search with relevant keywords |
35
56
 
36
57
  ---
37
58
 
@@ -7,11 +7,11 @@ description: Technographic data enrichment — discover what technologies, frame
7
7
 
8
8
  ## Available Methods
9
9
 
10
- | Method | Description | Credits |
11
- | --------------- | -------------------------------------- | ---------------------------- |
12
- | `lookupDomain` | Get full technology stack for a domain | 1 |
13
- | `relationships` | Find related/connected domains | 1 |
14
- | `searchByTech` | Find companies using a specific tech | 1/result (up to 900/page) |
10
+ | Method | Description | Credits |
11
+ | --------------- | -------------------------------------- | ------- |
12
+ | `lookupDomain` | Get full technology stack for a domain | 75 |
13
+ | `relationships` | Find related/connected domains | 75 |
14
+ | `searchByTech` | Find companies using a specific tech | 100 |
15
15
 
16
16
  ## Use Cases
17
17
 
@@ -31,7 +31,7 @@ description: Technographic data enrichment — discover what technologies, frame
31
31
 
32
32
  - **Case-sensitive**: Use "Hubspot" not "HubSpot"
33
33
  - **Find exact names**: Use `lookupDomain` on a site to see correct tech names
34
- - **Pagination**: Each page returns up to 900 results (= 900 credits per page). Use `offset` from previous response to get next page.
34
+ - **Pagination**: Each page returns up to 900 results. Use `offset` from previous response to get next page. Each page costs 100 credits.
35
35
 
36
36
  ## Example Workflows
37
37
 
@@ -1,4 +1,4 @@
1
- /** Credits: 1 (standard). */
1
+ /** Credits: 75 (standard). */
2
2
 
3
3
  /**
4
4
  * Get the full technology stack for a domain.
@@ -1,4 +1,4 @@
1
- /** Credits: 1 (standard). */
1
+ /** Credits: 75 (standard). */
2
2
 
3
3
  /**
4
4
  * Find domains related to a given domain.
@@ -1,4 +1,4 @@
1
- /** Credits: 1 per result returned. Each page returns up to 900 results (= up to 900 credits per page). */
1
+ /** Credits: 100 (standard). Charged per call regardless of result count. */
2
2
 
3
3
  /**
4
4
  * Find companies/domains that use a specific technology.
@@ -39,17 +39,18 @@ Find employees at a company using database search (default) or web search.
39
39
 
40
40
  ## Input Parameters
41
41
 
42
- | Parameter | Type | Required | Description |
43
- | ----------------- | ----------------------- | -------- | ---------------------------------------------------------------- |
44
- | `companySlug` | `string` | One of | LinkedIn universal_name (e.g., "stripe") |
45
- | `linkedinUrl` | `string` | One of | Full LinkedIn URL |
46
- | `searchStrategy` | `"database"` \| `"web"` | No | Default: "database" |
47
- | `titleVariations` | `string[]` | For web | Title keywords. **Required for web strategy. Max 3 variations.** |
48
- | `titleSqlFilter` | `string` | No | Raw SQL for precise matching (database only) |
49
- | `limit` | `number` | No | Max results (default: 25, max: 100) |
50
- | `usOnly` | `boolean` | No | US-based only (default: true) |
51
- | `minConnections` | `number` | No | Min connections filter (default: 20) |
52
- | `offset` | `number` | No | Pagination offset (database only) |
42
+ | Parameter | Type | Required | Description |
43
+ | ------------------------- | ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | `companySlug` | `string` | One of | LinkedIn universal_name (e.g., "stripe") |
45
+ | `linkedinUrl` | `string` | One of | Full LinkedIn URL |
46
+ | `searchStrategy` | `"database"` \| `"web"` | No | Default: "database" |
47
+ | `titleVariations` | `string[]` | For web | Title keywords. **Required for web strategy. Max 3 variations.** |
48
+ | `titleSqlFilter` | `string` | No | Raw SQL for precise matching (database only) |
49
+ | `limit` | `number` | No | Max results (default: 25, max: 100) |
50
+ | `usOnly` | `boolean` | No | US-based only (default: true) |
51
+ | `minConnections` | `number` | No | Min connections filter (default: 20) |
52
+ | `offset` | `number` | No | Pagination offset (database only) |
53
+ | `requireVerifiedPosition` | `boolean` | No | Web only. When true (default), only returns employees with a verified B2B database position. Set false to include unverified profiles. |
53
54
 
54
55
  **Critical:** Provide `companySlug` OR `linkedinUrl`, not both. Website/domain input is NOT supported.
55
56
 
@@ -87,6 +88,7 @@ Pattern for other functions: replace `Engineering` with `Sales`, `Marketing`, `P
87
88
 
88
89
  ```typescript
89
90
  // Web strategy for C-Suite only (max 3 variations!)
91
+ // By default, only returns employees with a verified B2B database position
90
92
  const { employees } = await services.company.getEmployeesFromLinkedin({
91
93
  linkedinUrl: row.linkedinCompanyUrl,
92
94
  searchStrategy: "web",
@@ -95,7 +97,19 @@ const { employees } = await services.company.getEmployeesFromLinkedin({
95
97
  });
96
98
  ```
97
99
 
98
- **Note:** Web strategy accepts a maximum of 3 title variations. Keep them focused on the core title variants.
100
+ To include unverified profiles (found via Google but not confirmed in B2B database):
101
+
102
+ ```typescript
103
+ const { employees } = await services.company.getEmployeesFromLinkedin({
104
+ linkedinUrl: row.linkedinCompanyUrl,
105
+ searchStrategy: "web",
106
+ titleVariations: ["CEO", "founder", "co-founder"],
107
+ requireVerifiedPosition: false, // Allow unverified profiles
108
+ limit: 10
109
+ });
110
+ ```
111
+
112
+ **Note:** Web strategy accepts a maximum of 3 title variations. Keep them focused on the core title variants. When `requireVerifiedPosition` is true (default), the company must exist in the B2B database or an error is thrown.
99
113
 
100
114
  ---
101
115
 
@@ -57,6 +57,8 @@ interface B2BCompany {
57
57
  }
58
58
  ```
59
59
 
60
+ > Note: company industry coverage in the LinkedIn B2B DB can be sparse. `industry` and `industries` may be `null`, generic, or missing even when the company record exists, so do not rely on them as the only company classification signal.
61
+
60
62
  ### Extended (`extended: true`) - `B2BCompanyExtended`
61
63
 
62
64
  Full data from `lkd_company` + `company` tables. Includes everything from `B2BCompany` plus:
@@ -1,12 +1,14 @@
1
1
  ---
2
- description: Search LinkedIn B2B database for companies by domain, slug, or ID lookup
2
+ description: Search LinkedIn B2B database for companies by domain, slug, or ID lookup. NOT for prospecting — use web search for discovery.
3
3
  ---
4
4
 
5
5
  # Company LinkedIn Search
6
6
 
7
7
  **Credits: 1/result (per-result). Reserves based on query `LIMIT`.**
8
8
 
9
- > **The LinkedIn DB is a lookup tool, not a search engine.** Only fast indexed queries are allowed (under 3 seconds, max 2-table joins). Everything else falls back to `services.web.search` with `site:linkedin.com/company` patterns. **You MUST read `services/web/search` before using web search.**
9
+ > **🚫 PROSPECTING CHECK:** Are you using this to **discover new companies**? This service is almost never the right choice for prospecting. Use `services.web.search` with `site:linkedin.com/company` patterns for discovery. The only prospecting exception is **trivially simple indexed-column filters** (e.g. `industry_code = 4 AND country_code = 'US'`). Any query with keywords, descriptions, company names, ILIKE, or semantic matching = web search.
10
+
11
+ > Only fast indexed queries are allowed (under 3 seconds, max 2-table joins). Everything else falls back to `services.web.search`. **You MUST read `services/web/search` before using web search.**
10
12
 
11
13
  > **IMPORTANT:** These tables (`linkedin_company`, `linkedin_crunchbase_funding`, etc.) are in an **EXTERNAL B2B database** -- NOT accessible via `ctx.sql()`.
12
14
  >
@@ -0,0 +1,74 @@
1
+ # Get Company Revenue
2
+
3
+ Get company revenue, employee count, and firmographic data from a company domain.
4
+
5
+ **Credits: 2 (standard). Charged only if a valid result is returned.**
6
+
7
+ ## Input Parameters
8
+
9
+ | Parameter | Type | Required | Description |
10
+ | --------- | -------- | -------- | ------------------------------------------------------------------------- |
11
+ | `domain` | `string` | Yes | Company website domain (e.g., `stripe.com`, `https://www.salesforce.com`) |
12
+
13
+ Accepts any format: bare domain (`stripe.com`), with www (`www.stripe.com`), or full URL (`https://www.stripe.com/about`). The domain is automatically normalized.
14
+
15
+ ## Output
16
+
17
+ ```typescript
18
+ {
19
+ revenue: number | null; // USD (e.g., 5100000000 for $5.1B). Ranges averaged.
20
+ employees: number | null; // Count (e.g., 750 for "501-1,000"). Ranges averaged.
21
+ headquarters: string | null; // e.g., "San Francisco, California, United States"
22
+ industry: string | null; // e.g., "Business Intelligence (BI) Software, Software"
23
+ website: string | null; // e.g., "www.stripe.com"
24
+ funding: number | null; // USD (e.g., 8700000000 for $8.7B)
25
+ description: string | null; // Company description paragraph
26
+ sourceUrl: string | null; // The data source URL
27
+ }
28
+ ```
29
+
30
+ ## Examples
31
+
32
+ ### Basic Revenue Lookup
33
+
34
+ ```typescript
35
+ const companyData = await services.company.revenue({
36
+ domain: row.domain
37
+ });
38
+ return companyData.revenue; // 5100000000
39
+ ```
40
+
41
+ ### Extract Multiple Fields
42
+
43
+ ```typescript
44
+ const companyData = await services.company.revenue({
45
+ domain: row.website
46
+ });
47
+ return {
48
+ revenue: companyData.revenue,
49
+ employees: companyData.employees,
50
+ industry: companyData.industry,
51
+ hq: companyData.headquarters
52
+ };
53
+ ```
54
+
55
+ ### Filter by Revenue Size
56
+
57
+ ```typescript
58
+ const companyData = await services.company.revenue({
59
+ domain: row.domain
60
+ });
61
+ if (companyData.revenue && companyData.revenue > 1_000_000_000) {
62
+ return "Enterprise";
63
+ } else if (companyData.revenue && companyData.revenue > 100_000_000) {
64
+ return "Mid-Market";
65
+ }
66
+ return "SMB";
67
+ ```
68
+
69
+ ## Key Rules
70
+
71
+ 1. **Domain input only** — pass the company's website domain. URLs, bare domains, and www-prefixed domains all work.
72
+ 2. **Numbers are parsed** — revenue, employees, and funding are returned as numbers (not formatted strings). Ranges are averaged.
73
+ 3. **All fields nullable** — if the data source doesn't list a field (e.g., funding for a bootstrapped company), it returns `null`.
74
+ 4. **Handles normalization** — `https://www.stripe.com/about`, `www.stripe.com`, and `stripe.com` all resolve to the same company.
@@ -1,4 +1,4 @@
1
- /** Credits: 1/result (per-result). Reserves up to `limit` or `maxCrawledPlacesPerSearch` (default 100). Settles actual count. */
1
+ /** Credits: 10/result (per-result). Reserves up to `limit` or `maxCrawledPlacesPerSearch` (default 100). Settles actual count. */
2
2
 
3
3
  interface GoogleMapsScraperInput {
4
4
  /** Array of search terms to find places (e.g., ['grocery store', 'pizza restaurant']) */