# GIF Scroll Animation (`crawlerbros/gif-scroll-animation`) Actor

Generate an animated GIF that scrolls down a webpage.

- **URL**: https://apify.com/crawlerbros/gif-scroll-animation.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 8 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## GIF Scroll Animation

Generate an animated GIF that scrolls down a webpage. The actor opens the URL in a headless Chromium browser, captures one frame per scroll step, then assembles the frames into a GIF using Pillow. The GIF is saved to the run's key-value store; a companion record with metadata + a public GIF URL is pushed to the dataset.

### What it does

You provide a webpage URL; the actor:

1. Renders the page in headless Chromium at the configured viewport size.
2. Scrolls the page in `scrollStepPx`-sized increments, capturing a screenshot per step (up to `maxFrames`).
3. Optionally downscales each frame, then encodes them as a single GIF with Pillow.
4. Writes the GIF binary to the key-value store under `output.gif`.
5. Pushes one dataset record with `{url, gifUrl, frameCount, width, height, fileSizeBytes, frameDelayMs, scrapedAt}`.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `url` | string (required) | `https://apify.com` | Page to capture. Must start with `http://` or `https://`. |
| `viewportWidth` | integer | `1280` (320–2560) | Browser viewport width in pixels. |
| `viewportHeight` | integer | `720` (240–1440) | Browser viewport height in pixels. |
| `scrollStepPx` | integer | `250` (50–2000) | Pixels to scroll between captured frames. Smaller values → smoother animation but more frames. |
| `frameDelayMs` | integer | `200` (50–5000) | Per-frame delay encoded into the GIF. |
| `maxFrames` | integer | `60` (2–300) | Hard cap on captured frames so very tall pages don't run forever. |
| `downscaleFactor` | integer | `2` (1–8) | Resize each frame down by this integer factor before encoding. `1` = full resolution, `2` = half, `4` = quarter. Lower = sharper but bigger GIF. |
| `cookieWindowSelector` | string (optional) | – | CSS selector of a cookie-consent dismiss button (e.g. `button#accept-all`). Clicked after page load so the consent banner doesn't appear in every frame. |
| `waitToLoadPageMs` | integer | `0` (0–30000) | Extra wait (ms) after `networkidle` for async-loaded content (lazy images, animations) to settle before capture starts. |

#### Example input

```json
{
  "url": "https://apify.com",
  "viewportWidth": 1280,
  "viewportHeight": 720,
  "scrollStepPx": 250,
  "frameDelayMs": 200,
  "maxFrames": 40,
  "downscaleFactor": 2
}
````

### Output

The dataset receives a single record per run:

```json
{
  "url": "https://apify.com",
  "gifUrl": "https://api.apify.com/v2/key-value-stores/<kvs-id>/records/output.gif",
  "frameCount": 28,
  "width": 640,
  "height": 360,
  "aspectRatio": 1.778,
  "fileSizeBytes": 482113,
  "frameDelayMs": 200,
  "durationMs": 5600,
  "scrapedAt": "2026-04-26T14:23:11+00:00"
}
```

The GIF binary itself is stored under key `output.gif` in the run's default key-value store and is reachable at the public `gifUrl` shown above.

#### Output fields

- **`url`** — the source URL captured.
- **`gifUrl`** — public URL pointing to the rendered GIF in the key-value store.
- **`frameCount`** — how many frames were captured before reaching the bottom or `maxFrames`.
- **`width`** / **`height`** — final GIF dimensions in pixels (after `downscaleFactor`).
- **`aspectRatio`** — derived: `width / height` rounded to 3 decimal places.
- **`fileSizeBytes`** — encoded GIF size in bytes.
- **`frameDelayMs`** — per-frame delay used in the GIF.
- **`durationMs`** — derived: `frameDelayMs * frameCount` — total GIF duration in milliseconds.
- **`scrapedAt`** — ISO-8601 UTC timestamp.

### Use cases

- **Marketing previews** — generate a quick animated preview of a landing page for social media, slack messages, or PR demos.
- **Scroll-test recording** — visualise long pages for accessibility / visual-regression review.
- **Documentation screenshots** — capture a page-tour as a single embeddable GIF instead of multiple stills.
- **Visual diffs** — re-run on the same URL across deploys to compare scroll appearance over time.

### FAQ

**Does it need a proxy?**
No — the actor uses the run's default network. If you need to capture a page that's geo- or IP-restricted, configure proxy at the run level via Apify's run-options panel.

**How big can the GIF get?**
Pillow uses optimised palette quantisation and disposal=2 to keep frames small, but a 30-frame full-1280×720 capture is still ~8–12 MB. Use `downscaleFactor: 2` (default) to roughly quarter the size.

**Why does the GIF stop early?**

- Reached the bottom of the page (`scrollY + viewportHeight >= scrollHeight`).
- Hit `maxFrames`. Increase the limit if you have a very tall page.

**Why isn't it perfectly smooth?**
GIF can only encode 1×, 2×, 5×, 10× hundredths-of-a-second, and Pillow rounds to the nearest. For motion-graphics quality, render to MP4 instead (this actor doesn't do video).

**How do I get just the GIF without the dataset record?**
Run the actor and download `output.gif` from the run's key-value store (the URL is in the dataset record's `gifUrl`).

**The page didn't render — what happened?**
Some pages block headless Chromium with bot challenges. The actor emits a sentinel record `{type: "gif_scroll_error", reason: "capture_failed", ...}` rather than crashing. Try the page in a normal browser first to confirm it isn't paywalled or geo-blocked.

# Actor input Schema

## `url` (type: `string`):

The URL of the webpage to capture.

## `viewportWidth` (type: `integer`):

Browser viewport width.

## `viewportHeight` (type: `integer`):

Browser viewport height.

## `scrollStepPx` (type: `integer`):

How many pixels to scroll between each captured frame.

## `frameDelayMs` (type: `integer`):

Per-frame delay encoded into the GIF.

## `maxFrames` (type: `integer`):

Hard cap on frames captured (protects very-long pages from runaway runs).

## `cookieWindowSelector` (type: `string`):

CSS selector of a cookie-consent dismiss button to click after page load (e.g. button\[aria-label="Accept all"]). Skipped if not found.

## `waitToLoadPageMs` (type: `integer`):

Additional milliseconds to wait after networkidle before capturing the first frame. Use for sites with async/sliding content.

## `downscaleFactor` (type: `integer`):

Resize each frame down by this integer factor before encoding (1 = no resize, 2 = half, 3 = third). Lower factors → larger but sharper GIF.

## Actor input object example

```json
{
  "url": "https://apify.com",
  "viewportWidth": 1280,
  "viewportHeight": 720,
  "scrollStepPx": 250,
  "frameDelayMs": 200,
  "maxFrames": 60,
  "waitToLoadPageMs": 0,
  "downscaleFactor": 2
}
```

# 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 = {
    "url": "https://apify.com"
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/gif-scroll-animation").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 = { "url": "https://apify.com" }

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/gif-scroll-animation").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "url": "https://apify.com"
}' |
apify call crawlerbros/gif-scroll-animation --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/gif-scroll-animation",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "GIF Scroll Animation",
        "description": "Generate an animated GIF that scrolls down a webpage.",
        "version": "0.1",
        "x-build-id": "s08kcaU7nNqECwCMf"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/crawlerbros~gif-scroll-animation/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-crawlerbros-gif-scroll-animation",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/crawlerbros~gif-scroll-animation/runs": {
            "post": {
                "operationId": "runs-sync-crawlerbros-gif-scroll-animation",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/crawlerbros~gif-scroll-animation/run-sync": {
            "post": {
                "operationId": "run-sync-crawlerbros-gif-scroll-animation",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "url"
                ],
                "properties": {
                    "url": {
                        "title": "Page URL",
                        "pattern": "^https?://",
                        "type": "string",
                        "description": "The URL of the webpage to capture."
                    },
                    "viewportWidth": {
                        "title": "Viewport width (px)",
                        "minimum": 320,
                        "maximum": 2560,
                        "type": "integer",
                        "description": "Browser viewport width.",
                        "default": 1280
                    },
                    "viewportHeight": {
                        "title": "Viewport height (px)",
                        "minimum": 240,
                        "maximum": 1440,
                        "type": "integer",
                        "description": "Browser viewport height.",
                        "default": 720
                    },
                    "scrollStepPx": {
                        "title": "Scroll step (px)",
                        "minimum": 50,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "How many pixels to scroll between each captured frame.",
                        "default": 250
                    },
                    "frameDelayMs": {
                        "title": "Frame delay (ms)",
                        "minimum": 50,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Per-frame delay encoded into the GIF.",
                        "default": 200
                    },
                    "maxFrames": {
                        "title": "Max frames",
                        "minimum": 2,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Hard cap on frames captured (protects very-long pages from runaway runs).",
                        "default": 60
                    },
                    "cookieWindowSelector": {
                        "title": "Cookie consent selector",
                        "type": "string",
                        "description": "CSS selector of a cookie-consent dismiss button to click after page load (e.g. button[aria-label=\"Accept all\"]). Skipped if not found."
                    },
                    "waitToLoadPageMs": {
                        "title": "Extra wait after load (ms)",
                        "minimum": 0,
                        "maximum": 30000,
                        "type": "integer",
                        "description": "Additional milliseconds to wait after networkidle before capturing the first frame. Use for sites with async/sliding content.",
                        "default": 0
                    },
                    "downscaleFactor": {
                        "title": "Downscale factor",
                        "minimum": 1,
                        "maximum": 8,
                        "type": "integer",
                        "description": "Resize each frame down by this integer factor before encoding (1 = no resize, 2 = half, 3 = third). Lower factors → larger but sharper GIF.",
                        "default": 2
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
