scrapeunblocker-mcp 0.12.1 → 0.12.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.
package/README.md CHANGED
@@ -16,7 +16,7 @@ You bring your **own** API key. Nothing is shared or proxied through us.
16
16
  | `browse_page` | Run interactive browser `steps` on a page (click, type, select, scroll, wait), then return the resulting HTML. Not read-only: it acts on the website. |
17
17
  | `list_elements` | List a page's notable elements with a ready-to-use selector for each (selector discovery). |
18
18
  | `fetch_parsed` | Fetch a page and return AI-parsed structured JSON. |
19
- | `google_search` | Run a Google search and return the results page as JSON: organic results with real URLs, ads, AI Overview, People also ask, related searches, knowledge panel, news, videos, local and shopping results. |
19
+ | `google_search` | Run a Google search and return the results page as JSON: organic results with real URLs, favicons, sitelinks and ratings, ads, AI Overview, People also ask, related searches with links, knowledge panel, news, videos, local and shopping results. |
20
20
  | `fetch_markdown` | Fetch a page and return it as clean Markdown: the main content with absolute links, without scripts, styles, navigation or footer. Usually 2-25% the size of the HTML, so it is the cheap way for a model to read a page. |
21
21
  | `search_and_read` | Search Google and read the top results in one call: Google's AI Overview (when there is one), the first 1-5 result pages as Markdown, and the other results as title, URL and snippet. Billed as one search plus one request per page read. |
22
22
  | `list_plugins` | List the ready-made site plugins (100+: Amazon, Walmart, Zillow, Booking.com, Indeed, Google Trends, YouTube, App Store, Ahrefs, ...) with their parameters. Free - it calls nothing. |
package/dist/index.js CHANGED
@@ -1592,7 +1592,7 @@ var PLUGINS = [
1592
1592
  "category": "Search engines",
1593
1593
  "path": "/search/bing",
1594
1594
  "fixed": {},
1595
- "description": "Searches Bing for `keyword` in a real browser and returns the results page as JSON: `topAds`, `bottomAds`, `organic` (each with `position`, `title`, `url`, `displayedUrl`, `domain`, `description`), `relatedSearches` and `totalResults`. Same parameters and response shape as `/serpApi`. `proxy_country` sets both the market and the location the search is sent from, which decides the ads.",
1595
+ "description": "Searches Bing for `keyword` in a real browser and returns the results page as JSON: `topAds`, `bottomAds` (each with `advertiser`, `favicon` and `sitelinks`), `organic` (each with `position`, `title`, `url`, `displayedUrl`, `domain`, `description`, `source`, `favicon`, `date`, `sitelinks`, `rating`, `richSnippet`, `thumbnail`), `relatedSearches`, `relatedSearchLinks`, `aiOverview` (Bing's AI summary), `spellingCorrection` and `totalResults`. Same parameters as `/serpApi`. When page 1 is crowded by ads and holds few organic results, a one-page call also takes page 2's organic results at no extra charge. `proxy_country` sets both the market and the location the search is sent from, which decides the ads.",
1596
1596
  "params": [
1597
1597
  {
1598
1598
  "name": "keyword",
@@ -6801,7 +6801,7 @@ var PLUGINS = [
6801
6801
  "fixed": {
6802
6802
  "mode": "search"
6803
6803
  },
6804
- "description": "Searches Wellfound (formerly AngelList Talent) startup jobs by `role`, `location` or remote `role` (or a Wellfound search `url`) and returns `jobs`: `title`, `url`, the full `description`, `compensation` with parsed `salary` (`min`, `max`, `currency`) and `equity` (`min`, `max` in %), `jobType` (`full-time`, `part-time`, `contract`, `internship`), `locations`, `remote`, `remotePolicy` (`ONSITE`, `REMOTE`, `ONSITE_OR_REMOTE`, `HYBRID`), `acceptedRemoteLocations`, `yearsExperienceMin`/`Max`, `postedAt` and the hiring `company` (`name`, `slug`, `url`, `tagline`, `companySize`, `stage`, `badges`). A listing page holds 20 companies with up to 3 matching jobs each; by default the call returns one page, with `max_results` it pages through up to that many jobs. Totals: `totalJobs`, `totalCompanies`, `pageCount`, `nextPage`. `mode=job&job=<url>` returns one job in full: description (text and HTML), salary with period, the same `jobType` and `remotePolicy` values (the page's wording in `remotePolicyText`, plus `wfhFlexible`), skills, `visaSponsorship`, `relocation`, `hiresRemotelyIn`, preferred timezones, hiring contact, posting date, and the company's size, markets, badges, funding and founders. Billed one unit per page fetched (`pagesFetched`).",
6804
+ "description": "Searches Wellfound (formerly AngelList Talent) startup jobs by `role`, `location` or remote `role` (or a Wellfound search `url`) and returns `jobs`: `title`, `url`, the full `description`, `compensation` with parsed `salary` (`min`, `max`, `currency`) and `equity` (`min`, `max` in %), `jobType` (`full-time`, `part-time`, `contract`, `internship`), `locations`, `remote`, `remotePolicy` (`ONSITE`, `REMOTE`, `ONSITE_OR_REMOTE`, `HYBRID`), `acceptedRemoteLocations`, `yearsExperienceMin`/`Max`, `postedAt` and the hiring `company` (`name`, `slug`, `url`, `tagline`, `companySize`, `stage`, `badges`). A listing page holds 20 companies with up to 3 jobs each; by default the call returns one page, with `max_results` it pages through up to that many jobs. With a `role`, the jobs whose title carries the role's words come first, then the ones Wellfound files under the role, and the companies' other jobs Wellfound lists on the role's page are left out (`titleMatches` counts the first kind; `title_match=false` keeps the listing as Wellfound shows it). When `max_results` is given with a `location` and the role's page has too few title matches, the location's whole listing and then the role's remote jobs open to that location fill in, at no extra charge. Totals: `totalJobs`, `totalCompanies`, `pageCount`, `nextPage` (continues the role's listing). `mode=job&job=<url>` returns one job in full: description (text and HTML), salary with period, the same `jobType` and `remotePolicy` values (the page's wording in `remotePolicyText`, plus `wfhFlexible`), skills, `visaSponsorship`, `relocation`, `hiresRemotelyIn`, preferred timezones, hiring contact, posting date, and the company's size, markets, badges, funding and founders. Billed one unit per page fetched (`pagesFetched`).",
6805
6805
  "params": [
6806
6806
  {
6807
6807
  "name": "role",
@@ -6841,6 +6841,13 @@ var PLUGINS = [
6841
6841
  "required": false,
6842
6842
  "description": "How many jobs to collect across pages (1-500). Default: the whole first page (20 companies with up to 3 jobs each, usually 30-60 jobs). Each page fetched is one billed unit."
6843
6843
  },
6844
+ {
6845
+ "name": "title_match",
6846
+ "type": "boolean",
6847
+ "required": false,
6848
+ "description": "With a role (default true): keep the jobs whose title carries the role's words, then the ones Wellfound files under that role, and drop the other jobs Wellfound lists on the role's page. false: every job of the listing as Wellfound shows it.",
6849
+ "default": true
6850
+ },
6844
6851
  {
6845
6852
  "name": "proxy_country",
6846
6853
  "type": "string",
@@ -6857,7 +6864,7 @@ var PLUGINS = [
6857
6864
  "fixed": {
6858
6865
  "mode": "job"
6859
6866
  },
6860
- "description": "Searches Wellfound (formerly AngelList Talent) startup jobs by `role`, `location` or remote `role` (or a Wellfound search `url`) and returns `jobs`: `title`, `url`, the full `description`, `compensation` with parsed `salary` (`min`, `max`, `currency`) and `equity` (`min`, `max` in %), `jobType` (`full-time`, `part-time`, `contract`, `internship`), `locations`, `remote`, `remotePolicy` (`ONSITE`, `REMOTE`, `ONSITE_OR_REMOTE`, `HYBRID`), `acceptedRemoteLocations`, `yearsExperienceMin`/`Max`, `postedAt` and the hiring `company` (`name`, `slug`, `url`, `tagline`, `companySize`, `stage`, `badges`). A listing page holds 20 companies with up to 3 matching jobs each; by default the call returns one page, with `max_results` it pages through up to that many jobs. Totals: `totalJobs`, `totalCompanies`, `pageCount`, `nextPage`. `mode=job&job=<url>` returns one job in full: description (text and HTML), salary with period, the same `jobType` and `remotePolicy` values (the page's wording in `remotePolicyText`, plus `wfhFlexible`), skills, `visaSponsorship`, `relocation`, `hiresRemotelyIn`, preferred timezones, hiring contact, posting date, and the company's size, markets, badges, funding and founders. Billed one unit per page fetched (`pagesFetched`).",
6867
+ "description": "Searches Wellfound (formerly AngelList Talent) startup jobs by `role`, `location` or remote `role` (or a Wellfound search `url`) and returns `jobs`: `title`, `url`, the full `description`, `compensation` with parsed `salary` (`min`, `max`, `currency`) and `equity` (`min`, `max` in %), `jobType` (`full-time`, `part-time`, `contract`, `internship`), `locations`, `remote`, `remotePolicy` (`ONSITE`, `REMOTE`, `ONSITE_OR_REMOTE`, `HYBRID`), `acceptedRemoteLocations`, `yearsExperienceMin`/`Max`, `postedAt` and the hiring `company` (`name`, `slug`, `url`, `tagline`, `companySize`, `stage`, `badges`). A listing page holds 20 companies with up to 3 jobs each; by default the call returns one page, with `max_results` it pages through up to that many jobs. With a `role`, the jobs whose title carries the role's words come first, then the ones Wellfound files under the role, and the companies' other jobs Wellfound lists on the role's page are left out (`titleMatches` counts the first kind; `title_match=false` keeps the listing as Wellfound shows it). When `max_results` is given with a `location` and the role's page has too few title matches, the location's whole listing and then the role's remote jobs open to that location fill in, at no extra charge. Totals: `totalJobs`, `totalCompanies`, `pageCount`, `nextPage` (continues the role's listing). `mode=job&job=<url>` returns one job in full: description (text and HTML), salary with period, the same `jobType` and `remotePolicy` values (the page's wording in `remotePolicyText`, plus `wfhFlexible`), skills, `visaSponsorship`, `relocation`, `hiresRemotelyIn`, preferred timezones, hiring contact, posting date, and the company's size, markets, badges, funding and founders. Billed one unit per page fetched (`pagesFetched`).",
6861
6868
  "params": [
6862
6869
  {
6863
6870
  "name": "job",
@@ -7440,7 +7447,7 @@ var PLUGINS = [
7440
7447
  "category": "Reviews & Companies",
7441
7448
  "path": "/companies/crunchbase",
7442
7449
  "fixed": {},
7443
- "description": "With `organization` (a Crunchbase slug like 'stripe' or a crunchbase.com/organization/... URL) returns the organization as JSON: `name`, `slug`, `uuid`, `url`, `legalName`, `aliases`, `shortDescription`, `description`, `logo`, `website`, `headquarters` (city, region, country, continent), `operatingStatus`, `companyType`, `ipoStatus`, `stockSymbol` + `stockExchange`, `employeeRange`, `industries`, `industryGroups`, `hubTags`, CB `rank` with `rankDelta90d` (Crunchbase's 90-day trend score for the rank, from -10 to 10: positive means the company moved up the ranking, toward #1), `growthScore` and `heatScore` (0-100) with `growthScoreDelta90d` and `heatScoreDelta90d` (their change in points over 90 days), `founders`, `lastFundingType`, counts (`numFundingRounds`, `numInvestors`, `numAcquisitions`, `numInvestments`, `numEmployeeProfiles` ...), `acquiredBy`, `owner`, the latest `fundingRounds` (type, investors, lead investors, each with `name`, `slug`, `url`, `type` and `image` like every other company or person reference), `investors`, `acquisitions`, `investments`, `exits`, `subOrganizations`, `keyPeople` (title, start date), `boardMembers`, `similarCompanies`, `products`, `contactEmail`, `phone`, `socialLinks`, `webTraffic` (`monthlyVisits`, and `monthlyVisitsChange`, the month-over-month change as a fraction: 0.069 = +6.9%, -0.2 = -20%), `technology`, `predictions`, `events` (product launches, partnerships, awards, layoffs, key employee changes, legal proceedings, each with its press source), `offices` and recent `news`. Every one of the record's 73 keys is always present. Data Crunchbase shows only to paying users (founded / closed / IPO dates, funding totals, round dates and amounts, acquisition prices, exits, valuation) is null, and `paywalledFields` names the ones Crunchbase holds for this organization. With `query` instead, searches organizations by name and returns up to `max_results` (max 25) matches with `name`, `slug`, `url`, `shortDescription` and `logo`, plus the total `count` of matches. No Crunchbase login required.",
7450
+ "description": "With `organization` (a Crunchbase slug like 'stripe' or a crunchbase.com/organization/... URL) returns the organization as JSON: `name`, `slug`, `uuid`, `url`, `legalName`, `aliases`, `shortDescription`, `description`, `logo`, `website`, `headquarters` (city, region, country, continent), `operatingStatus`, `companyType`, `ipoStatus`, `stockSymbol` + `stockExchange`, `employeeRange`, `industries`, `industryGroups`, `hubTags`, CB `rank` with `rankDelta90d` (Crunchbase's 90-day trend score for the rank, from -10 to 10: positive means the company moved up the ranking, toward #1), `growthScore` and `heatScore` (0-100) with `growthScoreDelta90d` and `heatScoreDelta90d` (their change in points over 90 days), `founders`, `lastFundingType`, counts (`numFundingRounds`, `numInvestors`, `numAcquisitions`, `numInvestments`, `numEmployeeProfiles` ...), `acquiredBy`, `owner`, the latest `fundingRounds` (type, investors, lead investors, each with `name`, `slug`, `url`, `type` and `image` like every other company or person reference), `investors`, `acquisitions`, `investments`, `exits`, `subOrganizations`, `keyPeople` (title, start date), `boardMembers`, `similarCompanies`, `products`, `contactEmail`, `phone`, `socialLinks` (`linkedin`, `twitter`, `facebook`, `instagram`, `youtube`, `github`), `linkedinId` (the company's LinkedIn handle), `webTraffic` (`monthlyVisits`, and `monthlyVisitsChange`, the month-over-month change as a fraction: 0.069 = +6.9%, -0.2 = -20%), `technology`, `predictions`, `events` (product launches, partnerships, awards, layoffs, key employee changes, legal proceedings, each with its press source), `offices` and recent `news`. What Crunchbase leaves empty is filled from the company's own homepage when it states it: `seoDescription` (its meta description), `coverImage` (its share image), `foundedOn`, `employeeCount`, `headquarters.street` and `headquarters.postalCode` (its schema.org block), the social links, `contactEmail` and `phone`; `fromWebsite` lists the keys that came from the homepage. Every one of the record's 78 keys is always present. Data Crunchbase shows only to paying users (founded / closed / IPO dates, funding totals, round dates and amounts, acquisition prices, exits, valuation) is null, and `paywalledFields` names the ones Crunchbase holds for this organization. With `query` instead, searches organizations by name and returns up to `max_results` (max 25) matches with `name`, `slug`, `url`, `shortDescription` and `logo`, plus the total `count` of matches. No Crunchbase login required.",
7444
7451
  "params": [
7445
7452
  {
7446
7453
  "name": "organization",
@@ -7462,7 +7469,7 @@ var PLUGINS = [
7462
7469
  "category": "Reviews & Companies",
7463
7470
  "path": "/companies/crunchbase",
7464
7471
  "fixed": {},
7465
- "description": "With `organization` (a Crunchbase slug like 'stripe' or a crunchbase.com/organization/... URL) returns the organization as JSON: `name`, `slug`, `uuid`, `url`, `legalName`, `aliases`, `shortDescription`, `description`, `logo`, `website`, `headquarters` (city, region, country, continent), `operatingStatus`, `companyType`, `ipoStatus`, `stockSymbol` + `stockExchange`, `employeeRange`, `industries`, `industryGroups`, `hubTags`, CB `rank` with `rankDelta90d` (Crunchbase's 90-day trend score for the rank, from -10 to 10: positive means the company moved up the ranking, toward #1), `growthScore` and `heatScore` (0-100) with `growthScoreDelta90d` and `heatScoreDelta90d` (their change in points over 90 days), `founders`, `lastFundingType`, counts (`numFundingRounds`, `numInvestors`, `numAcquisitions`, `numInvestments`, `numEmployeeProfiles` ...), `acquiredBy`, `owner`, the latest `fundingRounds` (type, investors, lead investors, each with `name`, `slug`, `url`, `type` and `image` like every other company or person reference), `investors`, `acquisitions`, `investments`, `exits`, `subOrganizations`, `keyPeople` (title, start date), `boardMembers`, `similarCompanies`, `products`, `contactEmail`, `phone`, `socialLinks`, `webTraffic` (`monthlyVisits`, and `monthlyVisitsChange`, the month-over-month change as a fraction: 0.069 = +6.9%, -0.2 = -20%), `technology`, `predictions`, `events` (product launches, partnerships, awards, layoffs, key employee changes, legal proceedings, each with its press source), `offices` and recent `news`. Every one of the record's 73 keys is always present. Data Crunchbase shows only to paying users (founded / closed / IPO dates, funding totals, round dates and amounts, acquisition prices, exits, valuation) is null, and `paywalledFields` names the ones Crunchbase holds for this organization. With `query` instead, searches organizations by name and returns up to `max_results` (max 25) matches with `name`, `slug`, `url`, `shortDescription` and `logo`, plus the total `count` of matches. No Crunchbase login required.",
7472
+ "description": "With `organization` (a Crunchbase slug like 'stripe' or a crunchbase.com/organization/... URL) returns the organization as JSON: `name`, `slug`, `uuid`, `url`, `legalName`, `aliases`, `shortDescription`, `description`, `logo`, `website`, `headquarters` (city, region, country, continent), `operatingStatus`, `companyType`, `ipoStatus`, `stockSymbol` + `stockExchange`, `employeeRange`, `industries`, `industryGroups`, `hubTags`, CB `rank` with `rankDelta90d` (Crunchbase's 90-day trend score for the rank, from -10 to 10: positive means the company moved up the ranking, toward #1), `growthScore` and `heatScore` (0-100) with `growthScoreDelta90d` and `heatScoreDelta90d` (their change in points over 90 days), `founders`, `lastFundingType`, counts (`numFundingRounds`, `numInvestors`, `numAcquisitions`, `numInvestments`, `numEmployeeProfiles` ...), `acquiredBy`, `owner`, the latest `fundingRounds` (type, investors, lead investors, each with `name`, `slug`, `url`, `type` and `image` like every other company or person reference), `investors`, `acquisitions`, `investments`, `exits`, `subOrganizations`, `keyPeople` (title, start date), `boardMembers`, `similarCompanies`, `products`, `contactEmail`, `phone`, `socialLinks` (`linkedin`, `twitter`, `facebook`, `instagram`, `youtube`, `github`), `linkedinId` (the company's LinkedIn handle), `webTraffic` (`monthlyVisits`, and `monthlyVisitsChange`, the month-over-month change as a fraction: 0.069 = +6.9%, -0.2 = -20%), `technology`, `predictions`, `events` (product launches, partnerships, awards, layoffs, key employee changes, legal proceedings, each with its press source), `offices` and recent `news`. What Crunchbase leaves empty is filled from the company's own homepage when it states it: `seoDescription` (its meta description), `coverImage` (its share image), `foundedOn`, `employeeCount`, `headquarters.street` and `headquarters.postalCode` (its schema.org block), the social links, `contactEmail` and `phone`; `fromWebsite` lists the keys that came from the homepage. Every one of the record's 78 keys is always present. Data Crunchbase shows only to paying users (founded / closed / IPO dates, funding totals, round dates and amounts, acquisition prices, exits, valuation) is null, and `paywalledFields` names the ones Crunchbase holds for this organization. With `query` instead, searches organizations by name and returns up to `max_results` (max 25) matches with `name`, `slug`, `url`, `shortDescription` and `logo`, plus the total `count` of matches. No Crunchbase login required.",
7466
7473
  "params": [
7467
7474
  {
7468
7475
  "name": "query",
@@ -8559,7 +8566,7 @@ var PLUGINS = [
8559
8566
  "category": "SEO & Ads",
8560
8567
  "path": "/ads/meta-ad-library",
8561
8568
  "fixed": {},
8562
- "description": "Pulls a Facebook/Instagram advertiser's ads from the Meta Ad Library and returns them as JSON for competitor analysis: `ad_text`, `title`, `cta_text`/`cta_type`, `display_format` (image/video/DCO/carousel), `creatives` (image and video URLs), `link_url` (the landing page), `platforms`, `started_running`/`ended`, and `is_active`. `advertiser` is a Page name (keyword search) or a numeric Page ID (that advertiser's whole set). Meta scopes the library by `country`. Use `active_status` ('active'/'inactive'/'all') and `media_type` to filter, and `max_ads` to bound the result.",
8569
+ "description": "Pulls a Facebook/Instagram advertiser's ads from the Meta Ad Library and returns them as JSON for competitor analysis. Each ad: `ad_archive_id`, `ad_library_url`, `collation_id`/`collation_count`, `ad_text`, `title`, `caption`, `cta_text`/`cta_type`, `link_url` (the landing page), `link_description`, `display_format` (image/video/DCO/carousel), `creatives` plus the same media split as `images`, `videos` and `cards`, `extra_texts`, `extra_links`, `categories`, `contains_sensitive_content`, `contains_digital_created_media`, `platforms`, `started_running`/`ended`, `is_active`, `total_active_time` (seconds), `impressions`, `spend`, `reach_estimate`, `targeted_or_reached_countries`, and the page: `page_id`, `page_name`, `page_profile_uri`, `page_profile_picture_url`, `page_like_count`, `page_categories`, `page_is_deleted`; each always present, null or [] when Meta shows none. The answer also echoes the `query` and the `search_url` read. `advertiser` is a Page name (keyword search) or a numeric Page ID (that advertiser's whole set). Meta scopes the library by `country` ('ALL' for every country). Use `active_status` ('active'/'inactive'/'all') and `media_type` to filter, and `max_ads` to bound the result.",
8563
8570
  "params": [
8564
8571
  {
8565
8572
  "name": "advertiser",
@@ -8571,7 +8578,7 @@ var PLUGINS = [
8571
8578
  "name": "country",
8572
8579
  "type": "string",
8573
8580
  "required": false,
8574
- "description": "Ad Library country (ISO-2, e.g. 'US', 'GB', 'DE'). Meta scopes the library by country.",
8581
+ "description": "Ad Library country (ISO-2, e.g. 'US', 'GB', 'DE'), or 'ALL' for every country. Meta scopes the library by country.",
8575
8582
  "default": "US"
8576
8583
  },
8577
8584
  {
@@ -8948,7 +8955,7 @@ ${body}`);
8948
8955
  }
8949
8956
 
8950
8957
  // src/index.ts
8951
- var VERSION = "0.12.1";
8958
+ var VERSION = "0.12.3";
8952
8959
  var DEFAULT_BASE_URL = "https://api.scrapeunblocker.com";
8953
8960
  var API_KEY_HEADER = "x-scrapeunblocker-key";
8954
8961
  function resolveApiKey() {
@@ -9339,7 +9346,7 @@ server.registerTool(
9339
9346
  {
9340
9347
  title: "Google search results",
9341
9348
  annotations: { title: "Google search results", readOnlyHint: true, openWorldHint: true, destructiveHint: false },
9342
- description: "Run a Google search through ScrapeUnblocker and return the results page as structured JSON: organic results with their real URLs, ads, the AI Overview, People also ask, related searches, the knowledge panel, top stories, videos, local and shopping results. Use this to discover URLs before fetching them.",
9349
+ description: "Run a Google search through ScrapeUnblocker and return the results page as structured JSON: organic results with their real URLs, favicons, sitelinks and star ratings, ads, the AI Overview, People also ask, related searches with their links, the knowledge panel, top stories, videos, local and shopping results. Use this to discover URLs before fetching them.",
9343
9350
  inputSchema: {
9344
9351
  keyword: z3.string().min(1).describe("The search query."),
9345
9352
  proxy_country: z3.string().length(2).optional().describe("Optional ISO country code to search from, e.g. 'US'."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrapeunblocker-mcp",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "mcpName": "com.scrapeunblocker/scrapeunblocker-mcp",
5
5
  "description": "Model Context Protocol (MCP) server for ScrapeUnblocker - lets Claude fetch any web page's HTML (or AI-parsed JSON) and run 100+ site plugins that return structured JSON, through the ScrapeUnblocker anti-bot API, using your own API key.",
6
6
  "keywords": [