# Google Doodles Scraper (`googleapi/google-doodles-scraper`) Actor

Scrape source-backed Google Doodle detail records: titles, release dates, complete public story text, themes, artwork/media, creator credits, and share links.

- **URL**: https://apify.com/googleapi/google-doodles-scraper.md
- **Developed by:** [Google API](https://apify.com/googleapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Scrape public Google Doodles archive pages and individual Doodle detail pages at [doodles.google](https://doodles.google/). Each dataset record describes one Doodle.

It extracts the title and stable page slug, the displayed publication and appearance dates, introductory copy, the full public About text, the Doodle's own key-theme links, its artwork/media URLs, creator-credit lines when present, public outbound links embedded in the story, and the share and related-Doodle links exposed on that page. Each outbound link includes its source label, exact destination URL, hostname, and nearest preceding section heading. Doodles-site navigation and social-share controls stay in their separate fields. Detail-page extraction is anchored to the `article` or `main` containing the Doodle title. Header, navigation, and footer content is excluded from media, share, and related-card extraction. Artwork linked to another Doodle is recorded as a related card rather than mixed into the current Doodle's media, and text-only links to other Doodles are not labeled as related items.

### Input

Direct detail-page example:

```json
{
  "startUrls": [
    { "url": "https://doodles.google/doodle/celebrating-hispanic-heritage-month-2026/" }
  ],
  "maxItems": 1
}
```

Search query example:

```json
{
  "queries": ["Halloween"],
  "maxItems": 2,
  "maxPages": 1,
  "includeDetails": true
}
```

`startUrls` accepts HTTPS archive, search, or `/doodle/<slug>/` pages on `doodles.google` (and its `www` host). `query` or `queries` builds the public archive URL using its `title_like` filter. `maxItems` is the global number of Doodle rows. `maxPages` limits supplied archive/search source pages. `includeDetails` defaults to false: explicitly enable it to add one bounded detail request per archive card for rich page fields. Direct detail start URLs always extract the requested detail page. Google uses “Show More” instead of a stable numbered archive-page URL, so `page` is limited to `1`.

For archive searches, the Actor follows the public “Show More” control within the selected limits. `maxPages` limits the number of archive/search pages; Google currently supports only page 1 for the page-number setting. `includeDetails` is off by default and adds one public detail-page request per discovered Doodle. You can optionally configure an Apify proxy for public requests. The Actor does not log in, solve CAPTCHAs, or bypass access controls. Google may limit public search results, so direct archive or detail URLs can be useful when a search does not return results.

### Dataset fields

Enriched detail records expose Doodle-specific source facts; card-only rows are smaller. Aliases, date components, duplicate media representations and derived counts are not independent facts. Core properties include:

- Identity and navigation: `doodleId`, `title`, `slug`, `pageUrl`, `canonicalPageUrl`, `archiveUrl` (`null` for a directly requested detail page)
- Dates: `publishedDate`, `publishedDateText`, date components, `appearedDate`, `appearedDateText`, `appearedDateUrl`
- Story: `description`, clean `descriptionHtml`, `aboutHeading`, full `aboutText` and clean `aboutHtml`, `launchText`, `whereAppearedText`. HTML retains paragraph/list/emphasis markup, with active content, controls and all attributes removed; source prose is not truncated.
- Artwork and geography: `artworkColor`, `artworkStyle`, `artworkForm`, exact `nationalityText` and structured `appearedCountries` from the public title-matched metadata and appearance map. Country coordinates are source map reference points, not artist locations or exact event locations. Nationality wording is not treated as artist citizenship. Runtime/analytics dates are not used as publication dates.
- Themes and media: `keyThemes`, `themeLabels`, `media`, `mediaImages`, `imageUrls`, `videoUrl`, `animationUrl`, `interactiveUrl`, nullable media-type flags
- Credits and links: `artistName`, structured `creatorCredits`, `externalLinks` / `externalLinkCount`, `shareOptions`, `relatedDoodles`
- Collection metadata: `themeCount`, `imageCount`, `shareOptionCount`, `externalLinkCount`, `relatedDoodleCount`, `contentLanguage`

Unknown source values remain `null`; a missing boolean is not turned into `false`. When `includeDetails` is true, search/archive rows are expanded into public detail pages. If a detail is unavailable, valid card identity, date, and artwork remain in the result. Archive-only rows contain fewer fields than detail-enriched rows.

### Output and access boundaries

Each dataset record represents one Doodle. Empty searches, blocked pages, and failed requests are reported in the run summary and logs rather than added as Doodle records.

You can download the dataset in formats such as JSON, HTML, CSV, or Excel. The run summary is available alongside the dataset in the Output tab. Detail enrichment adds extra requests and may increase compute use, so start with modest `maxItems` and `maxPages` values.

# Actor input Schema

## `startUrls` (type: `array`):

Public Google Doodles archive, search, or individual Doodle detail pages. Only doodles.google hosts are accepted.

## `query` (type: `string`):

Search the public Doodles archive by title. Empty static search shells are rendered in an ordinary browser, using the visible Show More control within finite limits.

## `queries` (type: `array`):

Multiple public archive title searches. Uses the public page and ordinary browser rendering, never private endpoints or fabricated matches.

## `maxItems` (type: `integer`):

Global maximum number of Doodle records to save across all supplied sources.

## `maxPages` (type: `integer`):

Maximum number of unique start or search pages to inspect. Each archive page may expand its cards into individual Doodle detail requests.

## `page` (type: `integer`):

Google currently exposes archive continuation through a Show More control rather than a stable numbered page URL. Only page 1 is supported; use startUrls to supply a specific public archive URL.

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

Optional existing Apify proxy for all public archive/detail HTTP requests and the complete fresh browser context. One configured route is used per run, with no rotation or direct fallback after an access boundary.

## `includeDetails` (type: `boolean`):

Opt in to one additional public Doodle detail request per discovered archive card. Default false; direct detail start URLs always extract that explicitly requested page.

## Actor input object example

```json
{
  "maxItems": 25,
  "maxPages": 10,
  "page": 1,
  "includeDetails": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("googleapi/google-doodles-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("googleapi/google-doodles-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 '{}' |
apify call googleapi/google-doodles-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,googleapi/google-doodles-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/OExKDGiXtvUCIBYDm/builds/s5Yc66AKDCxz1MXOW/openapi.json
