scrapercity 1.0.18 → 1.0.20

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.
package/AGENT_DOCS.txt CHANGED
@@ -193,6 +193,10 @@ GET /api/v1/database/leads?title=CTO&country=United States&hasEmail=true&page=1&
193
193
  Company filters: keywords (company tags, whole-word, any match), revenueMin, revenueMax (USD),
194
194
  companyCountry, companyState, companyCity (company HQ, not the person)
195
195
  Exclusions: notTitle, notKeywords, notIndustry
196
+ Website technologies (repeat the parameter for several): technologies (runs any of),
197
+ technologiesAll (runs all of), notTechnologies (runs none of). E.g. companies on
198
+ Klaviyo, PayPal and Shopify without Facebook Pixel:
199
+ technologiesAll=Klaviyo&technologiesAll=PayPal&technologiesAll=Shopify&notTechnologies=Facebook%20Pixel
196
200
  url=<people-search URL>: use that search's filters (other params override).
197
201
  The response adds search_translation: { applied, approximated, not_supported }.
198
202
  A URL with no filters the database can use returns 400.
@@ -251,6 +255,18 @@ GET /api/v1/database/local-businesses?category=Dentist&country=US&hasContact=tru
251
255
 
252
256
  GET /api/v1/database/ecommerce?...
253
257
  Same pattern (including excludeDelivered and after), different dataset.
258
+ Technologies: technologies (runs any of), technologiesAll (runs all of), notTechnologies
259
+ (runs none of), each repeatable, e.g. technologiesAll=Klaviyo&technologiesAll=PayPal&notTechnologies=Facebook%20Pixel
260
+
261
+ POST /api/v1/database/plan { "query": "dentists in Austin", "database": "local" }
262
+ (or GET /api/v1/database/plan?query=...&database=...)
263
+ $149/mo plan and up; planning does not count toward the daily limit. Plain English -> ready-to-run
264
+ database searches. query is who you want ("websites that
265
+ use shopify", "CEOs of SaaS companies in Texas") or what you sell ("I sell life insurance").
266
+ database (optional): leads | local | ecommerce; leave it out to let the planner pick.
267
+ Returns: { targeting, searches: [{ database, name, description, filters, count, apiEndpoint,
268
+ apiParams, link }] }. Filters use values the database really has; count leaves out
269
+ records this account already has. Send apiParams as they are to /api/v1/<apiEndpoint>.
254
270
 
255
271
  ────────────────────────────────────────
256
272
  ERROR CODES
package/SKILL.md CHANGED
@@ -78,9 +78,10 @@ Apollo scrapes take **up to 4 days** to deliver. Do NOT poll in a loop.
78
78
  | POST | `/api/v1/scrape/cancel/{runId}` | Cancel running job |
79
79
  | GET | `/api/v1/scrape/logs/{runId}` | Run logs |
80
80
  | GET | `/api/v1/apollo-status` | Apollo service health: `{status: "url-based" or "legacy", message, timestamp}` |
81
- | GET | `/api/v1/database/leads?title=CTO&country=United%20States&hasEmail=true&limit=100` | Lead DB ($149/mo plan and up, 100k new leads/day). Optional: `excludeDelivered=true` (only leads you don't have yet), `after=0` then `pagination.next_after` (cursor paging). Company filters: `keywords`, `revenueMin`/`revenueMax`, `companyCountry`/`companyState`/`companyCity`. Exclusions: `notTitle`, `notKeywords`, `notIndustry`. `url=<people-search URL>` searches with that URL's filters. POST with a JSON body takes the same parameters (use it for a long `url`) |
81
+ | GET | `/api/v1/database/leads?title=CTO&country=United%20States&hasEmail=true&limit=100` | Lead DB ($149/mo plan and up, 100k new leads/day). Optional: `excludeDelivered=true` (only leads you don't have yet), `after=0` then `pagination.next_after` (cursor paging). Company filters: `keywords`, `revenueMin`/`revenueMax`, `companyCountry`/`companyState`/`companyCity`. Exclusions: `notTitle`, `notKeywords`, `notIndustry`. Website technologies: `technologies` (any of), `technologiesAll` (all of), `notTechnologies` (none of). `url=<people-search URL>` searches with that URL's filters. POST with a JSON body takes the same parameters (use it for a long `url`) |
82
82
  | GET | `/api/v1/database/local-businesses?category=Dentist&country=US&hasContact=true&limit=100` | Local biz DB ($149/mo plan and up, 100k new businesses/day). Search like Google Maps: `keyword` (repeat; names and categories, any keyword) and `location` (repeat; cities, states, countries, postal codes), with `searched_as` in the response and `lead_database` when nothing is found but the Lead Database has 100+ people. Filters: `category`, `country`, `state`, `city`, `postalCode`, `query`, `minRating`/`maxRating`, `minReviews`/`maxReviews`, `hasEmail`, `hasPhone`, `hasWebsite`, `hasContact` (only businesses with a named contact person), `title` (business name), `box=minLat,minLng,maxLat,maxLng` (a map area). Exclusions: `notCategory`. `url=<Google Maps search URL>` searches with that URL's keyword and place. POST with a JSON body takes the same parameters (use it for a long `url`). Same optional `excludeDelivered` / `after` |
83
- | GET | `/api/v1/database/ecommerce?...` | Ecommerce DB ($149/mo plan and up). Same optional `excludeDelivered` / `after` |
83
+ | GET | `/api/v1/database/ecommerce?...` | Ecommerce DB ($149/mo plan and up). Same optional `excludeDelivered` / `after`. Technologies: `technologies` (any of), `technologiesAll` (all of), `notTechnologies` (none of) |
84
+ | POST | `/api/v1/database/plan` | $149/mo plan and up (GET with `?query=` also works). `{ "query": "dentists in Austin", "database"?: "leads" or "local" or "ecommerce" }` -> ready-to-run searches: `{ targeting, searches: [{ database, name, filters, count, apiEndpoint, apiParams, link }] }`. Send `apiParams` as they are to `/api/v1/<apiEndpoint>` |
84
85
 
85
86
  ## Status Values
86
87
  `RUNNING` → `SUCCEEDED` or `FAILED` or `CANCELLED`
package/bin/cli.mjs CHANGED
@@ -380,10 +380,13 @@ async function main() {
380
380
  '--keywords': 'keywords', '--revenue-min': 'revenueMin', '--revenue-max': 'revenueMax',
381
381
  '--company-country': 'companyCountry', '--company-state': 'companyState',
382
382
  '--company-city': 'companyCity', '--not-title': 'notTitle',
383
- '--not-keywords': 'notKeywords', '--not-industry': 'notIndustry' }
383
+ '--not-keywords': 'notKeywords', '--not-industry': 'notIndustry',
384
+ '--technologies': 'technologies', '--technologies-all': 'technologiesAll',
385
+ '--not-technologies': 'notTechnologies' }
384
386
  // List filters take commas: --country "United States,Canada" sends both.
385
387
  const lists = new Set(['--industry', '--country', '--state', '--seniority', '--department',
386
- '--company-country', '--company-state', '--not-industry'])
388
+ '--company-country', '--company-state', '--not-industry',
389
+ '--technologies', '--technologies-all', '--not-technologies'])
387
390
  for (const f of Object.keys(keyFor)) {
388
391
  const v = flag(f)
389
392
  if (v === undefined) continue
@@ -441,6 +444,22 @@ async function main() {
441
444
  break
442
445
  }
443
446
 
447
+ // ── Plan: plain English -> database searches ($149/mo plan and up) ──
448
+ case 'plan': {
449
+ const database = flag('--database')
450
+ const query = args.join(' ').trim()
451
+ if (!query) die('Usage: scrapercity plan "dentists in Austin" [--database leads|local|ecommerce]')
452
+ const r = await sc.planSearch(query, typeof database === 'string' ? database : undefined)
453
+ if (r.targeting) console.log(r.targeting)
454
+ for (const s of r.searches || []) {
455
+ console.log(`\n${s.name} (${s.database}): ${Number(s.count || 0).toLocaleString()} matches`)
456
+ console.log(` ${s.apiEndpoint}: ${JSON.stringify(s.apiParams)}`)
457
+ console.log(` ${s.link}`)
458
+ }
459
+ if (!(r.searches || []).length) console.log('No search found for that. Try naming who or what you want.')
460
+ break
461
+ }
462
+
444
463
  // ── Poll (convenience) ────────────────────────────────
445
464
  case 'poll': {
446
465
  if (!args[0]) die('Usage: scrapercity poll <runId> [--interval 15]')
@@ -491,12 +510,17 @@ ScraperCity CLI - B2B lead generation from your terminal
491
510
  scrapercity logs <runId> View run logs
492
511
  scrapercity runs [--hours 24] List recent runs
493
512
 
513
+ Plan ($149/mo plan and up):
514
+ scrapercity plan "dentists in Austin" Plain English -> ready-to-run database searches
515
+ --database leads|local|ecommerce Only this database (default: the ones that fit)
516
+
494
517
  Database ($149/mo plan and up):
495
518
  scrapercity db-leads [filters] Query lead database
496
519
  --title --industry --country --state --city --company --domain --seniority --department
497
520
  --min-employees --max-employees --has-email --has-phone
498
521
  --keywords --revenue-min --revenue-max --company-country --company-state --company-city
499
522
  --not-title --not-keywords --not-industry
523
+ --technologies --technologies-all --not-technologies Website technologies: any of / all of / none of (comma separated)
500
524
  --url "<people-search URL>" Search with that URL's filters
501
525
  --exclude-delivered Only leads you don't already have
502
526
  --after <id> Cursor paging (start with 0, then use the printed next id)
package/bin/mcp.mjs CHANGED
@@ -48,9 +48,17 @@ const UTILITY_TOOLS = [
48
48
  description: 'Cancel a running scraper job.',
49
49
  inputSchema: { type: 'object', properties: { runId: { type: 'string', description: 'The run ID to cancel' } }, required: ['runId'] }
50
50
  },
51
+ {
52
+ name: 'plan_search',
53
+ description: 'Turn a plain-English request into ready-to-run database searches. Describe who you want ("dentists in Austin", "websites that use Shopify", "CEOs of SaaS companies in Texas") or what you sell ("I sell life insurance"). Returns a few searches, each with its database, filters set to values that database really has, how many records match (leaving out what this account already has), a dashboard link, and apiParams to pass as they are to the matching query tool: query_lead_database for database/leads, query_local_business_database for database/local-businesses, query_ecommerce_database for database/ecommerce. Included with the $149/mo plan, like the database tools. Use it before a database query whenever you are not sure of the exact filter values.',
54
+ inputSchema: { type: 'object', properties: {
55
+ query: { type: 'string', description: 'What you are looking for or what you sell, in plain English' },
56
+ database: { type: 'string', enum: ['leads', 'local', 'ecommerce'], description: 'Optional: plan in this database only (leads = people at companies, local = local businesses, ecommerce = online stores). Leave it out to let the planner pick the databases that fit.' }
57
+ }, required: ['query'] }
58
+ },
51
59
  {
52
60
  name: 'query_lead_database',
53
- description: 'Query the B2B lead database directly. Returns contacts with names, emails, phones, titles, companies (plus company website, revenue, HQ location and keywords). Up to 100 per request. Included with the $149/mo plan (100,000 new leads a day; leads you already have do not count again). For a daily pull of only new leads set excludeDelivered=true. For big pulls page with after: send after="0" first, then the pagination.next_after from each response until it is null. Have a saved people-search URL? Pass it as url to search with its filters right away (search_translation in the response says what was applied).',
61
+ description: 'Query the B2B lead database directly. Returns contacts with names, emails, phones, titles, companies (plus company website, revenue, HQ location and keywords). Up to 100 per request. Included with the $149/mo plan (100,000 new leads a day; leads you already have do not count again). For a daily pull of only new leads set excludeDelivered=true. For big pulls page with after: send after="0" first, then the pagination.next_after from each response until it is null. Have a saved people-search URL? Pass it as url to search with its filters right away (search_translation in the response says what was applied). Target by the technologies a company\'s website runs: technologies (any of), technologiesAll (all of), notTechnologies (none of), e.g. technologiesAll ["Klaviyo", "PayPal", "Shopify"] with notTechnologies ["Facebook Pixel"].',
54
62
  inputSchema: { type: 'object', properties: {
55
63
  url: { type: 'string', description: 'A people-search URL (the address of a people search with its filters). Its filters become the search; any other filter you pass overrides the matching one.' },
56
64
  title: { type: 'string', description: 'Job title filter, comma separated for several (partial match, e.g. "CEO, Founder")' },
@@ -73,6 +81,9 @@ const UTILITY_TOOLS = [
73
81
  notTitle: { type: 'string', description: 'Exclude titles containing any of these (comma separated)' },
74
82
  notKeywords: { type: 'array', items: { type: 'string' }, description: 'Exclude companies with any of these keywords' },
75
83
  notIndustry: { type: 'array', items: { type: 'string' }, description: 'Exclude these industries' },
84
+ technologies: { type: 'array', items: { type: 'string' }, description: 'Companies whose website runs ANY of these technologies, e.g. ["HubSpot"]' },
85
+ technologiesAll: { type: 'array', items: { type: 'string' }, description: 'Companies whose website runs ALL of these technologies, e.g. ["Klaviyo", "PayPal"] (keep it to 1-3)' },
86
+ notTechnologies: { type: 'array', items: { type: 'string' }, description: 'Leave out companies whose website runs any of these technologies, e.g. ["Facebook Pixel"]' },
76
87
  socialUrl: { type: 'string', description: 'Match a social profile URL' },
77
88
  hasEmail: { type: 'boolean', description: 'Only contacts with email' },
78
89
  hasPhone: { type: 'boolean', description: 'Only contacts with phone' },
@@ -114,7 +125,7 @@ const UTILITY_TOOLS = [
114
125
  },
115
126
  {
116
127
  name: 'query_ecommerce_database',
117
- description: 'Query the ecommerce store database directly. Returns online stores with platform, estimated monthly sales and visits, employee count, emails, phones and social links. Up to 100 per request. Included with the $149/mo plan (100,000 new stores a day; stores you already have do not count again). For a daily pull of only new stores set excludeDelivered=true. For big pulls page with after: send after="0" first, then the pagination.next_after from each response until it is null.',
128
+ description: 'Query the ecommerce store database directly. Returns online stores with platform, estimated monthly sales and visits, employee count, emails, phones and social links. Up to 100 per request. Included with the $149/mo plan (100,000 new stores a day; stores you already have do not count again). For a daily pull of only new stores set excludeDelivered=true. For big pulls page with after: send after="0" first, then the pagination.next_after from each response until it is null. Combine technologies (any of), technologiesAll (all of) and notTechnologies (none of) for exact targeting, e.g. technologiesAll ["Klaviyo", "PayPal"] with notTechnologies ["Facebook Pixel"].',
118
129
  inputSchema: { type: 'object', properties: {
119
130
  platform: { type: 'array', items: { type: 'string' }, description: 'Ecommerce platforms, e.g. ["shopify", "woocommerce"] (any match)' },
120
131
  country: { type: 'array', items: { type: 'string' }, description: 'Two-letter country codes, e.g. ["US"]' },
@@ -124,6 +135,8 @@ const UTILITY_TOOLS = [
124
135
  merchant: { type: 'string', description: 'Merchant name (partial match)' },
125
136
  domain: { type: 'string', description: 'Store domain(s), comma or space separated' },
126
137
  technologies: { type: 'array', items: { type: 'string' }, description: 'Technologies the store uses (any match)' },
138
+ technologiesAll: { type: 'array', items: { type: 'string' }, description: 'Stores that run ALL of these technologies, e.g. ["Klaviyo", "PayPal"]' },
139
+ notTechnologies: { type: 'array', items: { type: 'string' }, description: 'Leave out stores that run any of these technologies, e.g. ["Facebook Pixel"]' },
127
140
  planExclude: { type: 'array', items: { type: 'string' }, description: 'Exclude stores on these plan tiers, e.g. ["Shopify Plus"]' },
128
141
  salesMin: { type: 'number', description: 'Minimum estimated monthly sales, USD' },
129
142
  salesMax: { type: 'number', description: 'Maximum estimated monthly sales, USD' },
@@ -166,6 +179,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
166
179
  break
167
180
  }
168
181
  case 'cancel_run': result = await sc.cancel(args.runId); break
182
+ case 'plan_search': result = await sc.planSearch(args.query, args.database); break
169
183
  case 'query_lead_database': {
170
184
  const params = { ...args }
171
185
  if (params.hasEmail) params.hasEmail = 'true'
@@ -1,6 +1,6 @@
1
1
  // AUTO-GENERATED by scripts/generate.mjs — DO NOT EDIT BY HAND.
2
2
  // Source of truth: scraperConfigs.ts (+ src/config/scrapers.ts). Regenerate: npm run generate
3
- // Generated: 2026-10-18T15:59:27.714Z
3
+ // Generated: 2026-10-20T21:18:28.662Z
4
4
  export const TOOLS = [
5
5
  {
6
6
  "name": "scrape_apollo",
@@ -542,7 +542,7 @@ export const TOOLS = [
542
542
  "properties": {
543
543
  "technology": {
544
544
  "type": "string",
545
- "description": "Technology name to search for (e.g., WordPress, Shopify, HubSpot)"
545
+ "description": "Technology name to search for (e.g., WordPress, Shopify, HubSpot, Klaviyo). Any technology in the Tech Stack Scraper's list, including the store apps the E-commerce Database tracks."
546
546
  },
547
547
  "fileName": {
548
548
  "type": "string",
@@ -661,5 +661,6 @@ export const ENDPOINTS = {
661
661
  "database-enrichment": "/api/v1/enrich",
662
662
  "database-local-business-enrichment": "/api/v1/enrich/local-businesses",
663
663
  "database-local-businesses": "/api/v1/database/local-businesses",
664
- "database-ecommerce": "/api/v1/database/ecommerce"
664
+ "database-ecommerce": "/api/v1/database/ecommerce",
665
+ "database-plan": "/api/v1/database/plan"
665
666
  }
package/lib/client.mjs CHANGED
@@ -208,6 +208,10 @@ export const dbEcommerce = (params) => {
208
208
  return get(`${ENDPOINTS['database-ecommerce']}?${qs}`)
209
209
  }
210
210
 
211
+ // Plain English -> ready-to-run database searches ($149/mo plan and up). database: 'leads' | 'local' | 'ecommerce', or leave it out.
212
+ export const planSearch = (query, database) =>
213
+ post('/api/v1/database/plan', database ? { query, database } : { query })
214
+
211
215
  // ── Poll until done ───────────────────────────────────────────
212
216
  export async function pollUntilDone(runId, { interval = 15000, timeout = 3600000, onStatus } = {}) {
213
217
  const start = Date.now()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrapercity",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "ScraperCity CLI & MCP Server - B2B lead generation for AI agents",
5
5
  "type": "module",
6
6
  "bin": {