# Google Search Results Scraper: Knowledge Panel & Answer Box (`api-empire/google-search-results-scraper`) Actor

Scrape Google Search results with Knowledge Panels, Answer Boxes, featured snippets, organic results, ads, URLs, titles, and descriptions. Extract structured SERP data for SEO research, competitor analysis, keyword tracking, and search intelligence.

- **URL**: https://apify.com/api-empire/google-search-results-scraper.md
- **Developed by:** [API Empire](https://apify.com/api-empire) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Google Search Results Scraper — Organic, Answer Box & Knowledge Panel

Google search results scraper that returns three distinct pieces of the SERP as typed JSON: every organic result, the featured snippet (`answerBox`), and the right-hand entity card (`knowledgePanel`) — plus paid ads, People Also Ask, and Google's own related-searches block. Every response is normalized, no HTML, no CSS selectors, no parsing step. There is no login wall and no API key required to run it. Point it at a keyword list or a batch of Google Search URLs and get back organic results, the answer box, and the knowledge panel in the same structured row.

### What is Google Search Results Scraper With Knowledge Panel & Answer Box?

It is a Google SERP scraper built on top of a base organic-results scraper, extended to also parse the featured snippet and the right-hand knowledge/entity panel that Google renders next to the ten blue links. Both blocks are stripped by `udm=14`, the URL parameter the base organic request sends by default, so this Actor fires a second, `udm`-free request (page 1 only) to read them. No Google account or login is required — it reads the public SERP the same way a browser would.

- Scrape organic results — title, URL, description, site links, position
- Scrape the answer box — featured-snippet type, answer text/HTML, list or table rows, citation
- Scrape the knowledge panel — entity title, subtitle, description with source, official website, `kc:` fact rows, social profiles
- Also returns paid ads, paid shopping products, People Also Ask, and Google's real related-searches block
- Export as JSON, CSV, Excel, or XML from the Apify dataset — no proxy management, no parsing

### What data does Google Search Results Scraper With Knowledge Panel & Answer Box collect?

Every dataset row can carry organic results, the answer box, and the knowledge panel side by side, plus the supporting SERP blocks below.

| Data Type | Key Fields | JSON Field Names |
| --- | --- | --- |
| Organic results | title, URL, description, site links, position | `organicResults[].title`, `.url`, `.description`, `.siteLinks`, `.position` |
| Answer box (featured snippet) | snippet type, answer text/HTML, list/table rows, citation | `answerBox.type`, `.answer`, `.listItems`, `.tableRows`, `.sourceUrl` |
| Knowledge panel | entity title/subtitle/type, description + source, website, fact rows, social profiles | `knowledgePanel.title`, `.entityType`, `.facts[].label`, `.facts[].value`, `.socialProfiles[]` |
| Paid results & products | ad title, URL, price | `paidResults[]`, `paidProducts[].prices` |
| People Also Ask | related question, link | `peopleAlsoAsk[].question`, `.url` |
| Related searches | Google's own related-search phrases | `relatedSearches[].title`, `.url` |

⚠️ The answer box and knowledge panel are parsed from **page 1 only** of each query, even when `maxPagesPerQuery` is set higher — Google only ever renders these two blocks on the first results page, so a second fetch on page 2+ would just find nothing there.

#### Need more Google data?

If you also need business reviews, app-store listings, or academic citations, API-Empire publishes dedicated Actors for those: **Google Maps Reviews Scraper With Reviewer Profile Details** for review data, **Google Play Scraper & Developer Catalog** for app listings, and **Google Scholar Scraper: Native Citations & Versions** for citation data. For a lighter organic-only scrape without the entity/answer-box layer, see **Google Search Results (SERP) Scraper By Site & File Type**, the base this Actor extends.

### How does Google Search Results Scraper With Knowledge Panel & Answer Box differ from Google's official Search API?

Google's own Custom Search JSON API is closed to new customers and is being sunset: per Google's developer documentation (checked 2026-08-16), existing customers have until **January 1, 2027** to move off it, and it never exposed a featured-snippet or knowledge-panel field to begin with — it returns curated results from a Programmable Search Engine, not the live public SERP.

| Feature | Custom Search JSON API | This Actor |
| --- | --- | --- |
| Open to new signups | Closed to new customers | Open — run it from the Apify Console with no account approval |
| Service lifetime | Discontinued for existing customers on Jan 1, 2027 | No sunset date published |
| Search scope | A configured Programmable Search Engine (custom index or whole-web mode) | The live `google.com` SERP for any query |
| Answer box / featured snippet | Not documented in the API reference | `answerBox` object with type, text/HTML, citation |
| Knowledge panel / entity card | Not documented in the API reference | `knowledgePanel` object with facts and social profiles |
| Setup | Google Cloud project, API key, Search Engine ID (`cx`) | Apify account, no Google credentials |

If you already hold a grandfathered Custom Search API key and only need indexed-page metadata, it remains usable until the 2027 cutoff. For a live SERP with the answer box and knowledge panel, or if you never had API access to begin with, this Actor is the practical option.

### Why do developers and teams scrape Google search results?

#### 🤖 For AI engineers and agent builders

The `answerBox` and `knowledgePanel` blocks are the two SERP elements Google itself uses to answer a query directly — exactly the signal an AEO/GEO workflow needs to track whether a brand's page is being cited as the source of a featured snippet or shown inside an entity panel. Feed `answerBox.sourceUrl`, `answerBox.answer`, and `knowledgePanel.facts` straight into a RAG index or an agent's tool-call response; combine with the `aiMode` and `perplexitySearch`/`chatGptSearch` add-ons to compare how Google AI Mode, Perplexity, and ChatGPT answer the same query side by side.

#### 📈 For SEO teams and marketers

`hasAnswerBox` and `hasKnowledgePanel` flag which of your tracked keywords currently show a featured snippet or an entity panel, and `answerBox.sourceUrl` tells you who owns it. Run the same keyword list on a schedule and diff the `knowledgePanel.facts` array to catch when a competitor's entity card picks up a new fact row, a new social profile, or loses its knowledge panel entirely.

#### 🔬 For researchers and analysts

Because every field comes straight off the public SERP — no login, no personalization applied beyond `countryCode`/`languageCode`/`locationUule` — this is public-data-only scope suited to studying how Google surfaces information for a given query set: how often an answer box appears for a topic, which domains it cites, and how `resultsTotal` and organic composition shift by country or by date range (`beforeDate`/`afterDate`).

#### 🏗️ For developers building data products

`organicResults`, `answerBox`, and `knowledgePanel` are stable, typed JSON keys you can pipe straight into a database or dashboard without an HTML-parsing layer of your own to maintain. Combine with the `maximumLeadsEnrichmentRecords` add-on to turn a keyword list into a domain-to-contact pipeline in the same run, and schedule it on Apify Schedules for a recurring rank/entity-tracking product.

### How to scrape Google search results (step by step)

1. Open the Actor's page on the Apify Store and click **Try for free** (or **Run** if you already have it saved).
2. Fill in `queries` — one search term or a full Google Search URL per line; this is the only required input.
3. Optionally set filters — `countryCode`, `languageCode`, `site`, `wordsInTitle`/`wordsInText`/`wordsInUrl`, `fileTypes`, `beforeDate`/`afterDate` — and toggle `captureAnswerBox`/`captureKnowledgePanel` (both on by default).
4. Click **Start** and watch rows arrive in the dataset in real time, one per query per page.
5. Export the results from the **Storage** tab as JSON, CSV, Excel, or XML, or pull them programmatically with the Apify API.

#### What to do when Google changes its SERP structure

The Actor is maintained and its output schema is kept stable — `organicResults`, `answerBox`, and `knowledgePanel` keep the same field names and types even when Google changes the underlying HTML, so integrations built against this schema keep working without changes on your end.

### What changed in Google search recently?

Two access-model changes affect anyone scraping Google right now. First, Google's Custom Search JSON API — the only official way to query Google Search programmatically — closed to new customers in 2025 and, per Google's own developer documentation (checked 2026-08-16), is fully discontinued for existing customers on January 1, 2027. Second, Google AI Mode moved from a Labs experiment (March 2025) to a default part of the search experience, rolled out broadly in the US at Google I/O in May 2025 and progressively to more countries since. For DIY scrapers this means the official API path is closing entirely, and any HTML scraper has to account for the `udm=14` AI-Mode-era layout that strips the answer box and knowledge panel from the default organic response — which is exactly the split request this Actor already implements via `entityRequestMode`. The public SERP itself — organic results, ads, the answer box, the knowledge panel — remains reachable without a login; maintenance of the parsing layer against future layout changes is ongoing.

### ⬇️ Input

`queries` is the only required field. Everything else has a working default.

| Parameter | Required | Type | Description |
| --- | --- | --- | --- |
| `queries` | **Yes** | string (textarea) | One search term or full Google Search URL per line. Supports Google operators (`site:`, `OR`, quotes). Keep each query under 32 words. |
| `resultsPerPage` | No | integer | Requested results per page, passed as Google's `num` param. Default `100`, min `1`, max `100`; clamped to that range even if bypassed. Google's own filtering means the actual count returned may be lower. |
| `maxPagesPerQuery` | No | integer | Pages to walk per query (~10 results/page). Default `1`, min `1`, **no maximum in the schema**. |
| `aiMode` | No | string (select) | Google AI Mode add-on ($). Default `"aiModeOff"`. Enum: `"aiModeOff"` (AI Mode off), `"aiModeWithSearchResults"` (AI Mode with search results), `"aiModeOnly"` (AI Mode only). |
| `serpApiKey` | No | string (secret) | Optional SerpApi key. Used only when `aiMode` is not off, to fetch the AI Overview via SerpApi. |
| `perplexitySearch` | No | object | Perplexity AI search add-on ($). Default `{"enablePerplexity": false, "searchRecency": "", "returnImages": false, "returnRelatedQuestions": false}`. Sub-fields: `enablePerplexity` (boolean, default `false`), `searchRecency` (string enum `""`/`"day"`/`"week"`/`"month"`/`"year"`, no default), `returnImages` (boolean, default `false`), `returnRelatedQuestions` (boolean, default `false`). |
| `chatGptSearch` | No | object | ChatGPT Search add-on ($). Default `{"enableChatGpt": false}`. Sub-field: `enableChatGpt` (boolean, default `false`). Adds `queryFanOut` to the output when enabled. |
| `maximumLeadsEnrichmentRecords` | No | integer | Business-leads enrichment add-on ($) — max leads to find per domain in the results. Default `0` (off), min `0`. Multiplies cost: 10 leads × 1,000 domains attempts 10,000 lookups; billed only for leads actually found. |
| `leadsEnrichmentDepartments` | No | array (select) | Restrict leads to departments. Default `[]`. Enum: `c-suite`, `product`, `engineering-technical`, `design`, `education`, `finance`, `human-resources`, `information-technology`, `legal`, `marketing`, `medical-health`, `operations`, `sales`, `consulting`. Only applies when `maximumLeadsEnrichmentRecords` > 0. |
| `focusOnPaidAds` | No | boolean | Ad-detection add-on ($) using an ad-specialized proxy and up to 3 retries per query. Default `false`. Extra cost per page applies when enabled, regardless of ads found. |
| `countryCode` | No | string (select) | Search country / Google domain, sent as `gl`. Default `"us"`. Full ISO country-code enum (~240 entries, e.g. `"gb"`, `"de"`, `"in"`) available in the input UI. |
| `searchLanguage` | No | string (select) | Restrict results to a language, sent as `lr`. No default (blank = unrestricted). ~35-entry language enum in the input UI. |
| `languageCode` | No | string (select) | Interface language (menus, not results), sent as `hl`. Default `"en"`. ~90-entry language enum in the input UI. |
| `locationUule` | No | string | Exact location code, sent as `uule`. Generate with a UULE code generator. |
| `forceExactMatch` | No | boolean | Wrap the query in quotes for an exact-phrase search. Default `false`. |
| `site` | No | string | Adds `site:<value>`. Takes precedence over `relatedToSite` if both are set. |
| `relatedToSite` | No | string | Adds `related:<value>`. Ignored if `site` is also set. |
| `wordsInTitle` | No | array of strings | Adds `intitle:"<word>"` per entry. Default `[]`, max 32 items. |
| `wordsInText` | No | array of strings | Adds `intext:"<word>"` per entry. Default `[]`, max 32 items. |
| `wordsInUrl` | No | array of strings | Adds `inurl:"<word>"` per entry. Default `[]`, max 32 items. |
| `quickDateRange` | No | string | Adds `tbs=qdr:<value>`, e.g. `d10`, `y1`. Avoid combining with `beforeDate`/`afterDate`. |
| `beforeDate` | No | string (date picker) | Absolute (`2024-05-03`) or relative (`8 days`, `3 months`) date, UTC. Adds a `cd_max` filter. |
| `afterDate` | No | string (date picker) | Absolute or relative date, UTC. Adds a `cd_min` filter. |
| `fileTypes` | No | array (select) | Adds `filetype:` operators, OR-combined when multiple selected. Default `[]`, max 10 items. Enum includes `pdf`, `csv`, `doc`, `docx`, `xls`, `xlsx`, `ppt`, `pptx`, `html`, `txt`, `xml`, `md`, `sql`, `mkv`, `mov`, and more (38 values total). |
| `mobileResults` | No | boolean | Mobile SERP layout instead of desktop. Default `false`. |
| `includeUnfilteredResults` | No | boolean | Include lower-quality results Google normally filters out (`tbs=li:1`). Default `false`. |
| `saveHtml` | No | boolean | Attach the raw page HTML to each dataset row under `html`. Default `false` — makes the dataset large. |
| `saveHtmlToKeyValueStore` | No | boolean | Store page HTML in the key-value store and link it via `htmlSnapshotUrl`. Default `true`. |
| `includeIcons` | No | boolean | Include Base64 favicon/icon data on results when found. Default `false`. |
| `proxyConfiguration` | No | object (proxy editor) | Requests always go through a proxy; prefilled to the `GOOGLE_SERP` Apify Proxy group. Escalates to `RESIDENTIAL` (with retries) when a response isn't a real results page. |
| `captureAnswerBox` | No | boolean | Parse the featured snippet into `answerBox`. Default `true`. Google only serves one on a minority of queries — expect `hasAnswerBox: false` on many rows. |
| `captureKnowledgePanel` | No | boolean | Parse the right-hand entity card into `knowledgePanel`. Default `true`. Entity queries only; reads `#rhs`, never the local/map pack. |
| `entityRequestMode` | No | string (select) | Default `"separate"`. Enum: `"separate"` (one extra `udm`-free request per query, page 1 only; organic output stays identical to the base), `"merged"` (drops `udm=14` from the one organic request — cheaper, but changes the organic result layout), `"off"` (no second request, no entity parsing). |
| `maxPanelFacts` | No | integer | Cap on `knowledgePanel.facts` entries. Default `25`, min `0`, max `100`. Panels typically expose 6–10 rows. |
| `onlyQueriesWithPanel` | No | boolean | Skip pushing (and charging for) any row with neither an answer box nor a knowledge panel. Default `false`. |
| `deduplicateAcrossPages` | No | boolean | Off (default): each page's row repeats every organic result from pages 1..n, matching the base Actor. On: each page's row carries only results first seen on that page. Charging is one `row_result` event per page either way. |

**Example input:**

```json
{
  "queries": "apple inc\nbest running shoes 2026",
  "resultsPerPage": 100,
  "maxPagesPerQuery": 1,
  "aiMode": "aiModeOff",
  "serpApiKey": "",
  "perplexitySearch": {
    "enablePerplexity": false,
    "searchRecency": "",
    "returnImages": false,
    "returnRelatedQuestions": false
  },
  "chatGptSearch": {
    "enableChatGpt": false
  },
  "maximumLeadsEnrichmentRecords": 0,
  "leadsEnrichmentDepartments": [],
  "focusOnPaidAds": false,
  "countryCode": "us",
  "searchLanguage": "",
  "languageCode": "en",
  "locationUule": "",
  "forceExactMatch": false,
  "site": "",
  "relatedToSite": "",
  "wordsInTitle": [],
  "wordsInText": [],
  "wordsInUrl": [],
  "quickDateRange": "",
  "beforeDate": "",
  "afterDate": "",
  "fileTypes": [],
  "mobileResults": false,
  "includeUnfilteredResults": false,
  "saveHtml": false,
  "saveHtmlToKeyValueStore": true,
  "includeIcons": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["GOOGLE_SERP"]
  },
  "captureAnswerBox": true,
  "captureKnowledgePanel": true,
  "entityRequestMode": "separate",
  "maxPanelFacts": 25,
  "onlyQueriesWithPanel": false,
  "deduplicateAcrossPages": false
}
```

The most common input mistake: setting `maxPagesPerQuery` above 1 expecting more answer-box/knowledge-panel rows — those two blocks are only ever read from page 1, so raising page count only adds more organic results, not more entity data.

### ⬆️ Output

Every run pushes typed, normalized JSON rows to the default dataset — no HTML, no selectors. Export as JSON, CSV, Excel, or XML from the Storage tab or the Apify API. A charged row uses the `row_result` pay-per-event; a failed query pushes an **uncharged** accounting row instead (see below).

#### Scraped search result row

```json
{
  "searchQuery": {
    "term": "apple inc",
    "url": "https://www.google.com/search?q=apple+inc&gl=us&hl=en&num=100",
    "device": "DESKTOP",
    "page": 1,
    "type": "SEARCH",
    "domain": "google.com",
    "countryCode": "US",
    "languageCode": "en",
    "locationUule": null,
    "resultsPerPage": 8
  },
  "searchQueryTerm": "apple inc",
  "url": "https://www.google.com/search?q=apple+inc&gl=us&hl=en&num=100",
  "hasNextPage": false,
  "serpProviderCode": "O",
  "resultsTotal": 1450000000,
  "relatedQueries": [
    { "title": "apple inc careers", "url": "https://www.google.com/search?q=apple+inc+careers" }
  ],
  "paidResults": [],
  "paidProducts": [],
  "aiOverview": null,
  "organicResults": [
    {
      "title": "Apple",
      "url": "https://www.apple.com/",
      "displayedUrl": "www.apple.com",
      "description": "Discover the innovative world of Apple and shop everything iPhone, iPad, Apple Watch, Mac and Apple TV.",
      "emphasizedKeywords": ["apple inc"],
      "siteLinks": [
        { "title": "iPhone", "url": "https://www.apple.com/iphone/", "description": "" }
      ],
      "productInfo": {},
      "type": "organic",
      "position": 1
    }
  ],
  "suggestedResults": [
    { "title": "apple inc careers", "url": "https://www.google.com/search?q=apple+inc+careers", "type": "related", "position": 1 }
  ],
  "peopleAlsoAsk": [
    { "answer": null, "question": "Who is the CEO of Apple Inc?", "title": "Who is the CEO of Apple Inc?", "url": "https://www.apple.com/leadership/", "date": null }
  ],
  "customData": {
    "perplexitySearch": { "enablePerplexity": false, "searchRecency": null, "returnImages": false, "returnRelatedQuestions": false },
    "chatGptSearch": { "enableChatGpt": false },
    "maximumLeadsEnrichmentRecords": 0,
    "leadsEnrichmentDepartments": []
  },
  "htmlSnapshotUrl": "apple_inc_20260816_101530_p1.html",
  "hasAnswerBox": false,
  "answerBox": null,
  "hasKnowledgePanel": true,
  "knowledgePanel": {
    "title": "Apple Inc.",
    "subtitle": "Technology company",
    "entityType": "organization",
    "description": "Apple Inc. is an American multinational technology company headquartered in Cupertino, California.",
    "descriptionSource": "Wikipedia",
    "descriptionUrl": "https://en.wikipedia.org/wiki/Apple_Inc.",
    "website": "https://www.apple.com/",
    "facts": [
      { "label": "CEO", "value": "Tim Cook", "valueUrl": null, "attrId": "kc:/organization/organization:ceo" },
      { "label": "Founded", "value": "April 1, 1976, Los Altos, CA", "valueUrl": null, "attrId": "kc:/organization/organization:founded" },
      { "label": "Headquarters", "value": "Cupertino, CA", "valueUrl": null, "attrId": "kc:/organization/organization:headquarters" }
    ],
    "socialProfiles": [
      { "network": "Twitter", "url": "https://twitter.com/Apple", "isGoogleRedirect": false }
    ]
  },
  "relatedSearches": [
    { "title": "apple inc careers", "url": "https://www.google.com/search?q=apple+inc+careers" }
  ],
  "entityExtraction": {
    "requestMode": "separate",
    "surfaceUrl": "https://www.google.com/search?q=apple+inc&gl=us&hl=en",
    "answerBoxSelector": null,
    "knowledgePanelContainer": "#rhs",
    "htmlSnapshotKey": "apple_inc_20260816_101530_entity.html",
    "error": null
  },
  "errorReason": null
}
```

`peopleAlsoAsk.answer` and `peopleAlsoAsk.date` are always `null` in the current parser — only `question`/`title` and `url` are populated. Add `saveHtml: true` to get the raw page HTML on the row itself (property `html`), on top of `searchQuery`, `url`, `hasNextPage`, `serpProviderCode`, `resultsTotal`, `relatedQueries`, `paidResults`, `paidProducts`, `aiOverview`, `organicResults`, `suggestedResults`, `peopleAlsoAsk`, `customData`, `htmlSnapshotUrl`, `hasAnswerBox`, `answerBox`, `hasKnowledgePanel`, `knowledgePanel`, `relatedSearches`, `entityExtraction`, and `errorReason` shown above.

#### Featured snippet (`answerBox`)

```json
{
  "type": "paragraph",
  "answer": "The capital of France is Paris, a major European city and a global center for art, fashion, gastronomy and culture.",
  "answerHtml": "<div class=\"g-blk\">…</div>",
  "listItems": [],
  "tableRows": [],
  "sourceTitle": "Paris - Wikipedia",
  "sourceUrl": "https://en.wikipedia.org/wiki/Paris",
  "sourceDisplayedUrl": "en.wikipedia.org/wiki/Paris"
}
```

`type` is one of `"paragraph"`, `"list"`, `"table"`, or `"video"`, detected from the block's own structure.

#### Knowledge panel (`knowledgePanel`)

```json
{
  "title": "Apple Inc.",
  "subtitle": "Technology company",
  "entityType": "organization",
  "description": "Apple Inc. is an American multinational technology company headquartered in Cupertino, California.",
  "descriptionSource": "Wikipedia",
  "descriptionUrl": "https://en.wikipedia.org/wiki/Apple_Inc.",
  "website": "https://www.apple.com/",
  "facts": [
    { "label": "CEO", "value": "Tim Cook", "valueUrl": null, "attrId": "kc:/organization/organization:ceo" }
  ],
  "socialProfiles": [
    { "network": "Twitter", "url": "https://twitter.com/Apple", "isGoogleRedirect": false }
  ]
}
```

⚠️ Google A/B-serves social-profile links in the panel two ways: a direct profile URL, or a `/goto?url=<opaque token>` redirect wrapper that cannot be decoded offline. `socialProfiles[].isGoogleRedirect` flags which one you got so it is never mistaken for a resolvable profile URL.

#### Uncharged failure row

A query that stays blocked through every retry rung, or resolves with no valid response, is never silently dropped and never billed — it is pushed with a distinct, smaller shape:

```json
{
  "searchQuery": { "term": "example query", "url": "", "device": "DESKTOP", "page": 1, "type": "SEARCH", "domain": "google.com", "countryCode": "US", "languageCode": "en", "locationUule": null, "resultsPerPage": 0 },
  "searchQueryTerm": "example query",
  "url": "",
  "status": "failed",
  "errorReason": "blocked_or_challenge_page",
  "charged": false,
  "hasAnswerBox": false,
  "answerBox": null,
  "hasKnowledgePanel": false,
  "knowledgePanel": null,
  "entityExtraction": { "requestMode": "separate", "surfaceUrl": null, "answerBoxSelector": null, "knowledgePanelContainer": null, "htmlSnapshotKey": null, "error": null }
}
```

Filter these out of a paid-row analysis with `item.charged !== false` (or equivalently, skip rows where `status === "failed"`). Note that `onlyQueriesWithPanel: true` behaves differently again: a page with neither block simply isn't pushed at all — it is skipped, not written as a failure row.

### How does Google Search Results Scraper With Knowledge Panel & Answer Box compare to other Google scrapers?

| Feature | This Actor | Generic alternative |
| --- | --- | --- |
| Answer box as a discrete field | ✅ `answerBox` object (type, text/HTML, citation) plus `hasAnswerBox` flag | ❌ Not documented as a separate field on Apify's own `apify/google-search-scraper` listing (checked 2026-08-16) |
| Knowledge panel granularity | ✅ Title, subtitle, entity type, sourced description, website, `facts[]`, `socialProfiles[]` | ❌ `dataharvest/google-search-scraper` documents a single flat `knowledgePanel` field without a documented facts/social-profile breakdown (checked 2026-08-16) |
| Snippet kept separate from organic results | ✅ Distinct `answerBox` block outside `organicResults` | ❌ `scrape.badger/google-search-scraper` documents the featured snippet as folded "within organic results' rich metadata" rather than a discrete block (checked 2026-08-16) |
| Cost/fidelity control over the panel fetch | ✅ `entityRequestMode`: separate request (byte-identical organic output) vs. merged (cheaper, changes organic layout) vs. off | ❌ Not documented as a configurable trade-off on any of the three listings checked 2026-08-16 |
| Uncharged failure accounting | ✅ Blocked/failed queries pushed as an uncharged row (`charged: false`) with `errorReason`, never silently dropped | ❌ Not documented on any of the three listings checked 2026-08-16 |

If you're building an AI agent or RAG pipeline, the output-format row is the decision-maker — parsing HTML for an answer box or entity card inside an agent loop is a reliability failure mode, not a feature.

### How many results can you scrape with Google Search Results Scraper With Knowledge Panel & Answer Box?

`resultsPerPage` is capped at 100 by the input schema (Google's `num` parameter) and clamped to `1`–`100` at runtime either way. `maxPagesPerQuery` has **no maximum in the schema** — set it as high as you need, and the Actor keeps paginating until Google's own next-page control (`#pnnext`) disappears from the SERP, or it hits the page you configured. Each page is roughly 10 organic results, though Google's own filtering can return fewer, especially on page 1; enabling `includeUnfilteredResults` can recover some of the difference. `answerBox` and `knowledgePanel` are read once per query, from page 1 only, regardless of `maxPagesPerQuery`. There is no measured throughput figure to report — actual results per run depend on your query list, `resultsPerPage`, and `maxPagesPerQuery`.

### Integrate Google Search Results Scraper With Knowledge Panel & Answer Box and automate your workflow

Google Search Results Scraper With Knowledge Panel & Answer Box works with any language or tool that can send an HTTP request to the Apify API.

#### REST API integration

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_API_TOKEN>")
run = client.actor("YOUR_USERNAME/google-search-results-scraper-knowledge-panel-answer-box").call(
    run_input={
        "queries": "apple inc\nbest running shoes 2026",
        "captureAnswerBox": True,
        "captureKnowledgePanel": True,
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["searchQueryTerm"], item["hasAnswerBox"], item["hasKnowledgePanel"])
```

Works in Python, Node.js, Go, Ruby, cURL.

#### Automation platforms (n8n, Make)

n8n's built-in **Apify node** and Make's **Apify module** can both call this Actor by name, poll the run, and drop dataset items straight into a downstream workflow — a scheduled rank/entity-tracking flow with no custom HTTP code needed.

### ⚖️ Is it legal to scrape Google search results?

Yes. Google Search Results Scraper With Knowledge Panel & Answer Box returns only what is publicly rendered on the Google SERP — organic results, ads, the answer box, the knowledge panel — the same information any visitor sees without logging in. This is business/product data, not personal data about identifiable individuals, so it sits under Google's Terms of Service and database/content-rights considerations rather than GDPR or CCPA, which govern personal data. The one exception is the optional business-leads enrichment add-on (`maximumLeadsEnrichmentRecords`): when enabled it returns names, emails, phone numbers, and LinkedIn profiles, which **is** personal data subject to GDPR/CCPA where applicable. Consult legal counsel for commercial use cases involving bulk personal data.

### ❓ Frequently asked questions

#### Does this Actor work without a Google account?

Yes. It reads the public Google SERP with no login and no Google API key. The only optional credential is a SerpApi key (`serpApiKey`), needed only if you enable the AI Mode add-on and want the AI Overview text.

#### How often is the scraped data updated?

Live. Every run sends a fresh request to `google.com` for each query — nothing is cached or replayed from a prior run.

#### What happens if a query has no answer box or no knowledge panel?

That's the common case, not an error. `hasAnswerBox`/`hasKnowledgePanel` are `false` and `answerBox`/`knowledgePanel` are `null` on that row; the organic results, ads, and People Also Ask are still returned normally. Set `onlyQueriesWithPanel: true` to skip (and avoid being charged for) rows with neither block.

#### Can this Actor return personalized or login-gated search results?

No. Only the public, unauthenticated SERP is scraped — no personalized results, no Search Console data, no content behind a site's own login wall. `countryCode`, `languageCode`, and `locationUule` change the market/locale Google serves, not personalization.

#### Do I need a Google API key to use this Actor?

No. It scrapes the public SERP directly rather than calling a Google API. The optional `serpApiKey` field is only for the AI Overview add-on, which uses a third-party service (SerpApi), not a Google credential.

#### Does this Actor work for AI agent workflows and LLM pipelines?

Yes. It's callable as an HTTP endpoint by any agent framework via the Apify API or `apify_client`. Every response is typed JSON — `organicResults`, `answerBox`, `knowledgePanel` — ready to pass into an LLM context window or agent tool call with no HTML parsing step.

#### How does this Actor handle Google's anti-bot defenses?

It runs through Apify's `GOOGLE_SERP` proxy group by default and escalates to `RESIDENTIAL` proxies (with retries and session rotation) when a response resolves to a `/sorry/` interstitial or Google's JS-challenge shell page — a real HTTP 200 response of roughly 92 KB that carries zero result containers. A page that clears that check but still parses to zero organic rows is treated as a soft block and retried with a fresh session before anything is pushed for that query.

#### How does this Actor compare to other Google scrapers?

Checked on the Apify Store on 2026-08-16: Apify's own `apify/google-search-scraper` documents organic results, ads, People Also Ask, and AI Overview, but not a separate answer-box or knowledge-panel field. `dataharvest/google-search-scraper` and `scrape.badger/google-search-scraper` both document a knowledge panel and snippet, but neither documents the separate-request vs. merged-request cost/fidelity trade-off (`entityRequestMode`) or an uncharged-failure-row guarantee that this Actor documents.

#### Does this Actor return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with stable field names — no HTML, no selectors, no parsing. Pass it directly into an LLM context window, index it into a vector store, or route it through an agent tool.

#### Can I use this Actor without managing proxies?

Yes. Proxying, including the escalation from Google SERP to residential proxies on a block, is handled internally. You can supply your own proxy configuration in `proxyConfiguration`, but it isn't required.

#### What happens when Google changes its SERP structure or blocks the scraper?

The Actor is maintained and the output schema stays stable — field names and types don't change on your end even when the underlying parsing logic has to adapt to a Google layout change.

### 💬 Your feedback

Found a bug or missing a field in the answer box or knowledge panel output? We want to know. Open an issue on the Actor's Apify Store page or contact API-Empire through the Console's built-in support channel — it's how this Actor stays maintained against Google's next layout change.

# Actor input Schema

## `queries` (type: `string`):

Use regular search words or enter Google Search URLs. You can also apply advanced Google search techniques, such as AI site:twitter.com or javascript OR python. You can also define selected search filters as separate fields below (in the Advanced search filters section). Just ensure that your queries do not exceed 32 words to comply with Google Search limits.

## `resultsPerPage` (type: `integer`):

Specifies the desired number of results per page that is passed to Google Search as the num parameter. However, Google applies its own internal filtering and quality checks, so the actual number of returned results may differ from this value, especially on the first page. To potentially retrieve more results closer to your desired count, consider enabling the "Unfiltered results" option from the "Additional settings" section below, which includes results that Google normally filters out.

## `maxPagesPerQuery` (type: `integer`):

Maximum number of pages to scrape per search query. Each page contains approximately 10 results.

## `aiMode` (type: `string`):

Enable scraping of Google's AI Mode to perform Answer Engine Optimization (AEO), GEO targeting, track brand visibility, and analyze competitors.

## `serpApiKey` (type: `string`):

Optional. When set and AI Mode is not off, fetches AI Overview via SerpApi.

## `perplexitySearch` (type: `object`):

Enable Perplexity to retrieve AI-generated answers and citations using the Sonar model. This feature is designed for cross-platform analysis, allowing you to directly compare Google AI Mode and ChatGPT results against Perplexity's perspective to identify narrative differences and coverage gaps.

Note: An additional fee applies per result when this feature is active. Please refer to the Pricing tab for your specific rate.

## `chatGptSearch` (type: `object`):

Enable ChatGPT to retrieve AI-generated answers powered by OpenAI's search model. This feature is designed for cross-platform analysis, allowing you to directly compare Google AI Mode and Perplexity results against ChatGPT's perspective to identify narrative differences, coverage gaps, and search engine biases.

The output includes query fan-out under queryFanOut, showing additional search queries the model generated to answer your question.

Note: An additional fee applies per result when this feature is active. Please refer to the Pricing tab for your specific rate.

## `maximumLeadsEnrichmentRecords` (type: `integer`):

Enrich your results with detailed contact and company information, including employee names, job titles, emails, phone numbers, LinkedIn profiles, and key company data like industry and number of employees.

This setting allows you to set the maximum number of leads records you want to scrape per each domain found. By default, it's set to 0 which means that no leads information will be scraped.

⚠️ Note that some of the fields contain personal data. GDPR protects personal data in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your use case is legitimate, please consult an attorney.

To keep your leads relevant, we automatically filter out large chains and online platforms (e.g., social media, retail giants, food delivery services).

⚠️ Cost warning: This is a multiplier. Requesting 10 leads for 1,000 domains will attempt to find 10,000 total leads. You are only charged for leads successfully found.

## `leadsEnrichmentDepartments` (type: `array`):

You can use this filter to include only specific departments (like Sales, Marketing, or C-Suite). Note: This will only work if the ⏩ Add-on: Extract business leads information - Maximum leads per domain (maximumLeadsEnrichmentRecords) option is enabled. Please note that some job titles are sometimes miscategorized in the wrong departments.

## `focusOnPaidAds` (type: `boolean`):

Enable extraction of paid results (Google Ads). This feature improves ad detection accuracy by using an ad-specialized proxy to perform up to 3 retries for each search query. Best used for queries likely to show ads. An extra cost per search page applies when enabled, regardless of ads found. Pricing depends on your Apify subscription plan.

## `countryCode` (type: `string`):

Specifies the country used for the search and the Google Search domain (e.g. google.es for Spain). By default, the Actor uses United States (google.com).

## `searchLanguage` (type: `string`):

Restricts search results to pages in a specific language. For example, choosing 'German' results in pages only in German. Passed to Google Search as the lr URL query parameter. Read more here.

## `languageCode` (type: `string`):

Language of the Google Search interface (menus, buttons, etc. - not the search results themselves). Passed to Google Search as the hl URL query parameter. From Google Reference: You can use the hl request parameter to identify the language of your graphical interface. The hl parameter value may affect search results, especially on international queries when language restriction (using the lr parameter) is not explicitly specified. Read more here.

## `locationUule` (type: `string`):

The code for the exact location for the Google search. It's passed to Google Search as the uule URL query parameter. You can use the UULE code generator. Learn more about emulating local search.

## `forceExactMatch` (type: `boolean`):

If checked, the scraper will search for the exact phrase in the query. This is done by wrapping the query in quotes. Note that this may return fewer results. Also note that if you're using operators such as OR or AND, the whole query will be wrapped in quotes, such as "Windows AND macOS". If you want to search for queries such as "Windows" AND "macOS", you need to specify them directly in the queries field.

## `site` (type: `string`):

Limits the search to a specific site, such as: site:example.com. Note that the site filter takes precedence over the relatedToSite filter. If both filters are set, the relatedToSite filter will be ignored and not added to the search queries.

## `relatedToSite` (type: `string`):

Filters pages related to a specific site, such as: related:example.com. Note that the site filter takes precedence over the relatedToSite filter. If both filters are set, the relatedToSite filter will be ignored and not added to the search queries.

## `wordsInTitle` (type: `array`):

Filters pages with specific words in the title. The scraper uses the intitle: operator, even for multiple words (e.g. recipe site:allrecipes.com intitle:"easy apple" intitle:pie). There's also a allintitle: operator available, but it's problematic when combined with other search filters, so the scraper avoids using it. If you need to use the allintitle: operator specifically, you can include it in your custom queries from the queries field.

## `wordsInText` (type: `array`):

Filters pages with specific words in the text. The scraper uses the intext: operator, even for multiple words (e.g. cartoon site:wikipedia.com intext:cat intext:mouse). There's also a allintext: operator available, but it's problematic when combined with other search filters, so the scraper avoids using it. If you need to use the allintext: operator specifically, you can include it in your custom queries from the queries field.

## `wordsInUrl` (type: `array`):

Filters pages with specific words in the URL. The scraper uses the inurl: operator, even for multiple words (e.g. recipe site:allrecipes.com inurl:apple inurl:pie). There's also a allinurl: operator available, but it's problematic when combined with other search filters, so the scraper avoids using it. If you need to use the allinurl: operator specifically, you can include it in your custom queries from the queries field.

## `quickDateRange` (type: `string`):

Filters results from a specific date range. d\[number] specifies the number of past days (e.g. the past 10 days can be written as d10). The same applies to hours, weeks, months, and years: h\[number], w\[number], m\[number], y\[number]. Example for the past year: 'y1' or even 'y'. The value is passed to Google Search using the tbs URL query parameter, prefixed with qdr:. You should avoid combining this filter with the beforeDate and afterDate filters to prevent conflicts.

## `beforeDate` (type: `string`):

Filters results from before the specified date. Either absolute date (e.g. 2024-05-03) or relative date from now into the past (e.g. 8 days, 3 months). Absolute time is always interpreted in the UTC timezone, not your local timezone - please convert accordingly. Supported relative date & time units: days, weeks, months, years. You should avoid combining this filter with the quickDateRange filter to prevent conflicts.

## `afterDate` (type: `string`):

Filters results from after the specified date. Either absolute date (e.g. 2024-05-03) or relative date from now into the past (e.g. 8 days, 3 months). Absolute time is always interpreted in the UTC timezone, not your local timezone - please convert accordingly. Supported relative date & time units: days, weeks, months, years. You should avoid combining this filter with the quickDateRange filter to prevent conflicts.

## `fileTypes` (type: `array`):

Filters results of specific file types using the filetype: operator, such as filetype:pdf. You can select multiple file types as well. They will be combined with the OR operator, for example: filetype:doc OR filetype:txt. If you need to use a file type that is not in the list (such as a source code file type), you can include it in your custom queries from the queries field, using the filetype: operator.

## `mobileResults` (type: `boolean`):

If checked the scraper will return results for mobile version of Google search. Otherwise desktop results are returned.

## `includeUnfilteredResults` (type: `boolean`):

If checked the lower quality results that Google normally filters out will be included.

## `saveHtml` (type: `boolean`):

If checked the HTML of the Google Search results pages will be stored to the default dataset, under the html property. This is useful if you need to process the HTML, but it makes the dataset large.

## `saveHtmlToKeyValueStore` (type: `boolean`):

If checked the HTML of the Google Search results pages will be stored to the default key-value store and links to the files stored to the dataset under the htmlSnapshotUrl property. This is useful for debugging since you can easily view the pages in the browser. However, the use of this feature may slow down the Actor.

## `includeIcons` (type: `boolean`):

If checked, all of the results (organicResults, paidResults, suggestedResults) will contain Base64-encoded icon image data if found.

## `proxyConfiguration` (type: `object`):

Requests always go through a proxy. The run starts on the Google SERP proxy and escalates to residential (3 retries, then sticky) when a response is not a real results page.

## `captureAnswerBox` (type: `boolean`):

Parse the featured-snippet block that sits above the ten blue links into answerBox (type, answer, answerHtml, listItems, tableRows and the citation). Google only serves a featured snippet on a minority of queries, so expect hasAnswerBox=false on many rows.

## `captureKnowledgePanel` (type: `boolean`):

Parse the right-hand entity card into knowledgePanel: title, subtitle, entityType, description with its source link, official website, kc: fact rows (CEO, founders, founded, headquarters, customer service phone, ...) and social profiles. Entity queries only - a panel is null when Google does not render one. This reads the #rhs entity card, never the local/map pack.

## `entityRequestMode` (type: `string`):

separate (default): one extra udm-free request per search term, page 1 only; the organic request keeps the base actor's exact parameters. merged: drop udm=14 from the single organic request and read everything from one page - cheaper, but the organic result set is the full SERP layout rather than the base's. off: no second request and no entity parsing at all.

## `maxPanelFacts` (type: `integer`):

Upper bound on knowledgePanel.facts entries. Entity panels typically expose 6-10 rows.

## `onlyQueriesWithPanel` (type: `boolean`):

When enabled, a page whose row carries neither a knowledge panel nor an answer box is not pushed to the dataset and is not charged. Useful for entity research over a large keyword list.

## `deduplicateAcrossPages` (type: `boolean`):

Off (default) reproduces the base actor's row shape: the row for page n repeats every organic result from pages 1..n. On, each page row carries only the results first seen on that page. Charging is one row\_result per page in both cases.

## Actor input object example

```json
{
  "queries": "javascript\ntypescript\npython",
  "resultsPerPage": 100,
  "maxPagesPerQuery": 1,
  "aiMode": "aiModeOff",
  "perplexitySearch": {
    "enablePerplexity": false,
    "searchRecency": "",
    "returnImages": false,
    "returnRelatedQuestions": false
  },
  "chatGptSearch": {
    "enableChatGpt": false
  },
  "maximumLeadsEnrichmentRecords": 0,
  "leadsEnrichmentDepartments": [],
  "focusOnPaidAds": false,
  "countryCode": "us",
  "languageCode": "en",
  "forceExactMatch": false,
  "wordsInTitle": [],
  "wordsInText": [],
  "wordsInUrl": [],
  "fileTypes": [],
  "mobileResults": false,
  "includeUnfilteredResults": false,
  "saveHtml": false,
  "saveHtmlToKeyValueStore": true,
  "includeIcons": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  },
  "captureAnswerBox": true,
  "captureKnowledgePanel": true,
  "entityRequestMode": "separate",
  "maxPanelFacts": 25,
  "onlyQueriesWithPanel": false,
  "deduplicateAcrossPages": false
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped items in the Actor's default dataset.

## `knowledgePanels` (type: `string`):

Per-query rows narrowed to the right-hand entity card (knowledgePanel) and whether one was found.

## `answerBoxes` (type: `string`):

Per-query rows narrowed to the featured snippet (answerBox) and whether one was found.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": `javascript
typescript
python`,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "GOOGLE_SERP"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("api-empire/google-search-results-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": """javascript
typescript
python""",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["GOOGLE_SERP"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("api-empire/google-search-results-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": "javascript\\ntypescript\\npython",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  }
}' |
apify call api-empire/google-search-results-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,api-empire/google-search-results-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/uV90wWuiI1fHf8NrB/builds/Dsq9AjDooX3WAShgt/openapi.json
