{
  "data": {
    "id": "ieif6txGzSc3k8mk0",
    "actId": "kcIeUfwCB7DUd1c2b",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-11-09T06:07:43.192Z",
    "finishedAt": "2026-11-09T06:07:53.231Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 9899,
      "runTimeSecs": 9.899,
      "computeUnits": 0.01099888888888889,
      "imageSizeBytes": 1354625024
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Twitter (X) Screenshot Generator\",\n  \"description\": \"Capture clean PNG screenshots of public X posts and profiles. No login or cookies required.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"postUrls\": {\n      \"title\": \"X post links, IDs or usernames\",\n      \"type\": \"array\",\n      \"description\": \"Posts to capture as clean post cards. Paste x.com or twitter.com links, bare numeric post IDs, profile links or bare usernames. Any input works in every list.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"https://x.com/NASA/status/2107095768821576019\"\n      ],\n      \"default\": []\n    },\n    \"tweetUrls\": {\n      \"title\": \"Tweet links (alias)\",\n      \"type\": \"array\",\n      \"description\": \"Alias of X post links. Accepts tweet links, bare tweet IDs, profile links and bare usernames.\",\n      \"editor\": \"stringList\",\n      \"default\": []\n    },\n    \"profileUrls\": {\n      \"title\": \"X profile links or usernames\",\n      \"type\": \"array\",\n      \"description\": \"Optional. Profiles to capture. Paste profile links, bare usernames, post links or post IDs and the actor routes them to the right capture. Use capture mode to choose the header only or the loaded profile preview.\",\n      \"editor\": \"stringList\",\n      \"default\": []\n    },\n    \"captureMode\": {\n      \"title\": \"Capture mode\",\n      \"type\": \"string\",\n      \"description\": \"What to capture. Post links produce a single post card or a thread image; profile modes apply to profile links (and convert post links to the author profile).\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"postCard\",\n        \"thread\",\n        \"profileHeader\",\n        \"fullProfilePage\"\n      ],\n      \"enumTitles\": [\n        \"Post card (one post)\",\n        \"Thread (root + contiguous author replies)\",\n        \"Profile header (header only)\",\n        \"Full profile page (loaded preview)\"\n      ],\n      \"default\": \"postCard\",\n      \"prefill\": \"postCard\"\n    },\n    \"theme\": {\n      \"title\": \"Theme\",\n      \"type\": \"string\",\n      \"description\": \"Color theme for the screenshot.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"dark\",\n        \"light\",\n        \"system\"\n      ],\n      \"enumTitles\": [\n        \"Dark\",\n        \"Light\",\n        \"System (browser default)\"\n      ],\n      \"default\": \"dark\",\n      \"prefill\": \"dark\"\n    },\n    \"bothThemes\": {\n      \"title\": \"Both themes\",\n      \"type\": \"boolean\",\n      \"description\": \"When on, every target is captured twice: once in dark and once in light. Files and rows are unique per theme (one screenshot row per theme) and the run summary reports both themes. Overrides the Theme selection.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"includeEvidence\": {\n      \"title\": \"Include evidence pack\",\n      \"type\": \"boolean\",\n      \"description\": \"Save a gzipped DOM snapshot and a JSON manifest to the key-value store for every capture, and add screenshotSha256, domSnapshotSha256, evidenceKey and manifestKey to each row. Failures still get a manifest with the typed failure state.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"fullPage\": {\n      \"title\": \"Full-page capture\",\n      \"type\": \"boolean\",\n      \"description\": \"When on, the whole page is captured instead of just the post card or the visible profile header.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"hideReplies\": {\n      \"title\": \"Hide replies\",\n      \"type\": \"boolean\",\n      \"description\": \"Hide reply posts so screenshots stay focused on original posts.\",\n      \"default\": true,\n      \"prefill\": true\n    },\n    \"includeMetadata\": {\n      \"title\": \"Include post/profile details\",\n      \"type\": \"boolean\",\n      \"description\": \"Add details to each row: post id, post URL, author handle, text snippet and the author's follower, following and post counts for posts; username, display name, follower, following and post counts for profiles. Counts are only added when X shows them.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"format\": {\n      \"title\": \"Image format\",\n      \"type\": \"string\",\n      \"description\": \"File format of the saved screenshot. JPEG and WEBP support the quality setting; PNG is lossless.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"png\",\n        \"jpeg\",\n        \"webp\"\n      ],\n      \"enumTitles\": [\n        \"PNG (lossless, largest)\",\n        \"JPEG (smaller file, quality setting applies)\",\n        \"WEBP (smallest file, quality setting applies)\"\n      ],\n      \"default\": \"png\",\n      \"prefill\": \"png\"\n    },\n    \"quality\": {\n      \"title\": \"Image quality\",\n      \"type\": \"integer\",\n      \"description\": \"Quality for JPEG and WEBP output (1-100). Ignored for PNG.\",\n      \"default\": 90,\n      \"prefill\": 90,\n      \"minimum\": 1,\n      \"maximum\": 100\n    },\n    \"deviceScaleFactor\": {\n      \"title\": \"Pixel density\",\n      \"type\": \"string\",\n      \"description\": \"Render the page at a higher pixel density for sharper screenshots. 2x doubles and 3x triples the pixel dimensions.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"1x\",\n        \"2x\",\n        \"3x\"\n      ],\n      \"enumTitles\": [\n        \"1x (standard)\",\n        \"2x (retina)\",\n        \"3x (high density)\"\n      ],\n      \"default\": \"1x\",\n      \"prefill\": \"1x\"\n    },\n    \"viewportWidth\": {\n      \"title\": \"Viewport width (pixels)\",\n      \"type\": \"integer\",\n      \"description\": \"Browser width used for the capture. Higher values fit more of the page.\",\n      \"default\": 1440,\n      \"minimum\": 320,\n      \"maximum\": 3840\n    },\n    \"viewportHeight\": {\n      \"title\": \"Viewport height (pixels)\",\n      \"type\": \"integer\",\n      \"description\": \"Browser height used for the capture.\",\n      \"default\": 900,\n      \"minimum\": 240,\n      \"maximum\": 2160\n    },\n    \"maxThreadHeight\": {\n      \"title\": \"Max thread height (px)\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum thread column height in CSS pixels; the saved image is DPR times taller. The value is clamped so the image cannot exceed the 32,767 px screenshot ceiling (10,922 CSS px at 3x). Taller threads are clipped and the row reports threadComplete=false with the truncation reason.\",\n      \"default\": 8000,\n      \"prefill\": 8000,\n      \"minimum\": 500,\n      \"maximum\": 20000,\n      \"sectionCaption\": \"Advanced\",\n      \"sectionDescription\": \"Optional settings for large or repeated runs.\"\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy configuration\",\n      \"type\": \"object\",\n      \"description\": \"Optional. Use a proxy if you plan large runs or see frequent rate limits.\",\n      \"editor\": \"proxy\",\n      \"nullable\": true\n    }\n  }\n}",
    "readme": "# Twitter (X) Screenshot Generator\r\n\r\nCapture clean screenshots of public X posts, threads and profiles — **no login, no cookies, no API key**. Paste post links to get pixel-perfect post cards or a contiguous thread image, or profile links to get the profile header or the loaded profile preview. Choose dark, light or system theme, PNG/JPEG/WEBP output, and 1x–3x pixel density. Capture dark and light in one run, and optionally save a verifiable evidence pack (gzipped DOM snapshot + JSON manifest with SHA-256 hashes).\r\n\r\n## What this actor does\r\n\r\n- **Four capture modes:** `postCard` (one post), `thread` (root post + contiguous same-author replies), `profileHeader` (header only) and `fullProfilePage` (the loaded profile preview)\r\n- **Verified targets:** the canonical post id and author handle are checked, so a short ID that resolves to another author is reported as `wrong_author` instead of a false success\r\n- **Honest failure states:** protected, deleted, missing and login-walled pages return typed, non-billable status rows\r\n- **Clean captures:** headers, sidebars, login prompts, the late \"Continue to X\" gate, sticky top bars, video player chrome and community notes are hidden automatically; the overlay hide is repeated after a 2.5s settle\r\n- **Image control:** PNG, JPEG or WEBP, quality setting for JPEG/WEBP, and real 1x/2x/3x pixel density with `effectiveScale` reported\r\n- **Custom viewport:** width and height from 320×240 up to 3840×2160\r\n- **Optional details:** post ID, URL, author handle, text snippet, and profile or author follower counts when X shows them\r\n- **Both themes in one run:** `bothThemes` captures dark and light versions with unique files and one row per theme\r\n- **Evidence pack:** `includeEvidence` saves a gzipped DOM snapshot and a JSON manifest to the key-value store, and reports `screenshotSha256`, `domSnapshotSha256`, `evidenceKey` and `manifestKey` on each row\r\n- **Empty fields are omitted:** never null, empty strings or empty arrays/objects.\r\n- **Run summary:** one `runSummary` row reports requested/captured/failed/billable counts, typed failure codes and dropped inputs\r\n- **Empty fields are omitted**\r\n\r\n## Output per screenshot\r\n\r\nEach row has a `type`: `screenshot` for a capture, `status` for a failure/run message, or `runSummary` for the end-of-run totals. If no post or profile link was provided at all, a single `status` row with `status: \"noInput\"` is emitted plus the summary; unsupported inputs are reported in `invalidInputs`.\r\n\r\n| Field | Description |\r\n|---|---|\r\n| `targetUrl` | The canonical post or profile URL that was captured (the requested URL on failures) |\r\n| `targetType` | `post` or `profile` |\r\n| `captureMode` | `postCard`, `thread`, `profileHeader` or `fullProfilePage` |\r\n| `status` | `success` or a friendly error description |\r\n| `code` | Typed failure code: `not_found`, `protected`, `deleted`, `login_wall`, `wrong_author`, `wrong_target`, `selector_miss`, `media_error`, `browser_crash`, `network_error`, `invalid_input` or `capture_error` |\r\n| `billable` | `true` only for captured screenshot rows |\r\n| `accessState` | `public`, `protected`, `deleted`, `not_found` or `login_wall` |\r\n| `requestedUrl`, `canonicalUrl` | The input URL and the canonical URL X served |\r\n| `width`, `height` | Dimensions of the captured image in pixels |\r\n| `format` | Saved image format (`png`, `jpeg` or `webp`) |\r\n| `fileSizeBytes` | Size of the saved image |\r\n| `filename` | File name in the key-value store, including mode/theme/format/DPR |\r\n| `downloadUrl` | Public signed HTTPS link to download the image (omitted when signing fails or only a local `file://` URL exists) |\r\n| `quality` | JPEG/WEBP quality setting used |\r\n| `deviceScaleFactor` | Pixel density used for the capture (1, 2 or 3) |\r\n| `effectiveScale` | Actual image pixels per CSS pixel |\r\n| `previewLimited`, `previewLimitReason` | Profile preview cap flags |\r\n| `thread` | Thread parts, length, gate position, completion and truncation reason (`thread` mode) |\r\n| `poll` | Poll choices with percentages and, when syndication is reachable, exact vote counts (`includeMetadata` only) |\r\n| `communityNote` | Readers-added-context id and text (`includeMetadata` only) |\r\n| `capturedAt`, `collectedAt`, `scrapedAt` | ISO timestamps of the capture |\r\n| `recordType` | `screenshot`, `status` or `runSummary` |\r\n| `sourceUrl` | Canonical target URL (`targetUrl`) when one exists |\r\n| `profileUrl` | The profile URL, on profile captures |\r\n| `theme` | The theme captured in this row (`dark` or `light`) |\r\n| `screenshotSha256` | SHA-256 of the saved image bytes (`includeEvidence` only) |\r\n| `domSnapshotSha256` | SHA-256 of the raw DOM snapshot before gzip (`includeEvidence` only) |\r\n| `evidenceKey` | Key-value store key of the gzipped DOM snapshot (`includeEvidence` only) |\r\n| `manifestKey` | Key-value store key of the JSON evidence manifest (`includeEvidence` only) |\r\n\r\nThe `runSummary` row contains `requested`, `captured`, `failed`, `skipped`, `billable`, `billableScreenshots`, `failureCodes`, `invalidInputs`, `theme`, `themes`, `format`, `deviceScaleFactor`, `captureMode`, `totalBytes`, `totalDurationMs`, `startedAt` and `finishedAt`. With **Both themes** on, `requested`/`captured` count both theme captures and `themes` is `[\"dark\", \"light\"]`.\r\n\r\nWith **Include post/profile details** on, post rows also carry `tweetId`, `tweetUrl`, `authorUsername`, `textSnippet`, `poll`, `communityNote`, `authorFollowers`, `authorFollowing` and `authorPostCount`; profile rows carry `username`, `name`, `followers`, `following` and `postCount`. Counts and poll/note fields are only added when X shows them.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `postUrls` | array | – | Post links, bare post IDs, profile links or bare usernames |\r\n| `tweetUrls` | array | – | Alias of post links |\r\n| `profileUrls` | array | – | Profiles to capture (header or full page, depending on capture mode) |\r\n| `captureMode` | string | `postCard` | `postCard`, `thread`, `profileHeader` or `fullProfilePage`. In profile modes, post links capture the post's author profile instead |\r\n| `theme` | string | `dark` | `dark`, `light` or `system` |\r\n| `bothThemes` | boolean | `false` | Capture dark and light versions of every target in one run; one row per theme and unique files |\r\n| `includeEvidence` | boolean | `false` | Save a gzipped DOM snapshot and JSON manifest to the key-value store and add SHA-256/evidence fields to rows |\r\n| `fullPage` | boolean | `false` | Capture the clipped post/profile column instead of just the card or header |\r\n| `hideReplies` | boolean | `true` | Hide reply posts so captures stay focused (ignored in `thread` mode, which keeps contiguous author parts) |\r\n| `includeMetadata` | boolean | `false` | Add post/profile details and counts to each row |\r\n| `format` | string | `png` | `png` (lossless), `jpeg` or `webp` |\r\n| `quality` | integer | `90` | Quality for JPEG/WEBP (1–100); ignored for PNG |\r\n| `deviceScaleFactor` | string | `1x` | `1x`, `2x` or `3x` pixel density reported as `effectiveScale` |\r\n| `viewportWidth` | integer | `1440` | Browser width used for the capture (320–3840) |\r\n| `viewportHeight` | integer | `900` | Browser height used for the capture (240–2160) |\r\n| `maxThreadHeight` | integer | `8000` | Maximum thread image height; taller threads are clipped and marked incomplete |\r\n| `proxyConfiguration` | object | – | Optional, for large or repeated runs |\r\n\r\nAt least one post link or profile link is required. Any input works in any list — links, IDs and usernames are routed automatically.\r\n\r\n### Example: post card\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"https://x.com/NASA/status/2107095768821576019\"],\r\n  \"theme\": \"dark\",\r\n  \"hideReplies\": true,\r\n  \"includeMetadata\": true\r\n}\r\n```\r\n\r\n### Example: thread\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"https://x.com/naval/status/1002103360646823936\"],\r\n  \"captureMode\": \"thread\",\r\n  \"maxThreadHeight\": 8000,\r\n  \"theme\": \"dark\",\r\n  \"includeMetadata\": true\r\n}\r\n```\r\n\r\n### Example: profile header\r\n\r\n```json\r\n{\r\n  \"profileUrls\": [\"https://x.com/apify\"],\r\n  \"captureMode\": \"profileHeader\",\r\n  \"theme\": \"light\",\r\n  \"viewportWidth\": 1280,\r\n  \"viewportHeight\": 800\r\n}\r\n```\r\n\r\n### Example: full profile page\r\n\r\n```json\r\n{\r\n  \"profileUrls\": [\"apify\"],\r\n  \"captureMode\": \"fullProfilePage\",\r\n  \"fullPage\": true\r\n}\r\n```\r\n\r\n### Example: high-density JPEG\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"2107095768821576019\"],\r\n  \"format\": \"jpeg\",\r\n  \"quality\": 85,\r\n  \"deviceScaleFactor\": \"2x\"\r\n}\r\n```\r\n\r\n### Example: both themes + evidence pack\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"https://x.com/NASA/status/2107095768821576019\"],\r\n  \"bothThemes\": true,\r\n  \"includeEvidence\": true,\r\n  \"includeMetadata\": true\r\n}\r\n```\r\n\r\nThis produces two screenshot rows (`theme: \"dark\"` and `theme: \"light\"`), each with its own image, `screenshotSha256`, `domSnapshotSha256`, `evidenceKey` and `manifestKey`. The evidence files live in the same key-value store as the images.\r\n\r\n### Example record\r\n\r\n```json\r\n{\r\n  \"type\": \"screenshot\",\r\n  \"targetUrl\": \"https://x.com/NASA/status/2107095768821576019\",\r\n  \"targetType\": \"post\",\r\n  \"captureMode\": \"postCard\",\r\n  \"theme\": \"dark\",\r\n  \"status\": \"success\",\r\n  \"width\": 1440,\r\n  \"height\": 810,\r\n  \"format\": \"png\",\r\n  \"fileSizeBytes\": 412345,\r\n  \"filename\": \"screenshot_2107095768821576019_postcard_dark_png_1x.png\",\r\n  \"downloadUrl\": \"https://api.apify.com/v2/key-value-stores/{STORE_ID}/records/screenshot_2107095768821576019_postcard_dark_png_1x.png?signature=...\",\r\n  \"deviceScaleFactor\": 1,\r\n  \"screenshotSha256\": \"5f2b...\",\r\n  \"domSnapshotSha256\": \"a91c...\",\r\n  \"evidenceKey\": \"evidence_screenshot_2107095768821576019_postcard_dark_png_1x.html.gz\",\r\n  \"manifestKey\": \"manifest_screenshot_2107095768821576019_postcard_dark_png_1x.json\",\r\n  \"capturedAt\": \"2026-10-06T10:30:00+00:00\",\r\n  \"tweetId\": \"2107095768821576019\",\r\n  \"tweetUrl\": \"https://x.com/NASA/status/2107095768821576019\",\r\n  \"authorUsername\": \"NASA\",\r\n  \"textSnippet\": \"It's World Space Week! ...\"\r\n}\r\n```\r\n\r\n## Limits\r\n\r\n- Public content only — protected accounts return a `protected` status row and cannot be captured.\r\n- Logged-out profiles show a loaded preview of roughly 5–10 posts (observed 5–10; it never grows with scrolling). `fullProfilePage` is that preview, not the infinite timeline, and rows set `previewLimited: true`. `profileHeader` is header-only by design.\r\n- Logged-out post pages render only the first ~4–10 replies. The `See all the replies / Continue to X` gate appears after scrolling; `/replies` is a 404/login redirect for guests, so deeper reply paging is not available.\r\n- Thread captures only contain the articles X renders in the logged-out DOM. A gate is reported as truncation only when its DOM position is before or inside the last captured part; a gate appended after the last article is the normal end of the preview. Non-author replies stop the contiguous block. Full unroll is not guaranteed.\r\n- `maxThreadHeight` is expressed in CSS pixels and is clamped automatically so the DPR-scaled image cannot exceed the 32,767 px screenshot ceiling (32,767 / 16,383 / 10,922 CSS px at 1x/2x/3x). Clipped threads report `threadComplete: false` with `truncatedReason: max_height` or `dpr_height_limit`.\r\n- Poll metadata is limited to the choices X renders or syndication binds (2–4 choices). Quote counts, places, full follower lists and sensitive flags are not available cookieless.\r\n- Community-note text is captured as text; the note is hidden from the image. The note id is included when the syndication/DOM link exposes it.\r\n- A bare short post ID can collide with an older post id. When the requested handle does not match the canonical author, the row fails with `wrong_author` rather than capturing the wrong post.\r\n- Metadata counts, poll and community-note fields are added only when X displays them.\r\n- Capture failures (for example a deleted post) produce a typed `status` row plus a `runSummary`, so a run is never silently empty or billed as a success.\r\n- **Both themes** doubles runtime, screenshots and dataset rows; files and evidence keys remain unique per theme.\r\n- **Include evidence pack** adds the DOM snapshot (gzipped, typically ~7% of the screenshot size) and a manifest per capture. The DOM is the post-hide rendered markup, not the raw HTTP response.\r\n- Evidence manifests are still written for failed captures (with `failure.code`, `failure.message` and `failure.accessState`) when the page is available; a crashed page may leave only the manifest.\r\n## Use cases\r\n\r\n- **Social media reporting** — embed clean post captures in decks, newsletters and blogs\r\n- **Brand monitoring** — archive screenshots of public posts as evidence\r\n- **Community management** — capture profile pages for creator or partner reviews\r\n- **Research** — build image datasets of public posts with consistent framing and theme\r\n- **Content creation** — generate post images for roundups without manual screenshotting\r\n- **Legal and compliance** — timestamped captures of public posts with source URLs, SHA-256 hashes and a DOM snapshot as an evidence trail\r\n\r\n## FAQ\r\n\r\n**Can I screenshot private accounts or posts?** No. Only public posts and profiles are accessible.\r\n\r\n**What resolution are the screenshots?** The viewport defaults to 1440×900 and is configurable from 320×240 up to 3840×2160. With `2x` or `3x` pixel density the saved image is two or three times larger on each side. The actual dimensions are always reported in `width` and `height`.\r\n\r\n**What is the difference between the capture modes?** `postCard` captures a single post as a clean card; `profileHeader` captures only the profile header (banner, avatar, name, bio, counts and tabs); `fullProfilePage` captures the loaded profile preview with its posts; `thread` captures the root post plus contiguous same-author replies. A post link captures a post card only in `postCard` mode — if `profileHeader` or `fullProfilePage` is selected, a post link captures that post's author profile instead.\r\n\r\n**Does it support threads?** Yes. Set `captureMode` to `thread` and the actor captures the root post plus the contiguous same-author replies as one image. Threads that hit a logged-out gate, a different author or `maxThreadHeight` are marked `threadComplete: false` with a truncation reason. The logged-out page only contains the articles X renders, so full unroll is not guaranteed.\r\n\r\n**What happens if a post contains a video?** The actor waits for the video to decode, pauses it, seeks to a representative frame, hides the player controls and applies a luma/poster guard against black frames before capturing.\r\n\r\n**What gets hidden in a capture?** The left navigation, headers, sidebars, login prompts, the late \"Continue to X\" gate, sticky top bars, video controls, empty fixed overlays and community notes are hidden automatically. The hide runs repeatedly after a 2.5s settle. Reply posts are hidden when **Hide replies** is on.\r\n\r\n**Which image format should I use?** PNG for lossless quality, JPEG for smaller files, WEBP for the smallest files. JPEG and WEBP use the quality setting.\r\n\r\n**What if a link is invalid or the post was deleted?** The row gets a typed `code` and a friendly `status` instead of a screenshot, marked `billable: false`. Protected, deleted, missing and login-walled pages are detected before the selector timeouts, and the run never crashes. The final `runSummary` row lists the counts and reasons.\r\n\r\n**Can I capture dark and light in one run?** Yes. Turn on **Both themes** and every target is captured twice, once dark and once light. Files include the theme in the name, so nothing is overwritten, and each theme gets its own dataset row and `theme` value. The run summary counts both captures and lists `themes: [\"dark\", \"light\"]`.\r\n\r\n**What is the evidence pack?** With **Include evidence pack** on, each capture also writes `evidence_<key>.html.gz` (the rendered DOM, gzipped) and `manifest_<key>.json` (target, capture metadata, dimensions, SHA-256 hashes, and failure state when the capture failed) to the key-value store. Rows get `screenshotSha256`, `domSnapshotSha256`, `evidenceKey` and `manifestKey`. Evidence is typically ~7% of the screenshot size; failures still get a manifest even when no image was produced.\r\n\r\n**How long do download links last?** They follow your Apify key-value store retention (typically 7 days on the free tier). Copy the images to your own storage for permanent archival.\r\n\r\n**Is this affiliated with X?** No. This is a third-party actor that captures publicly visible pages.\r\n\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "twitter-x-screenshot-generator",
      "title": "Twitter (X) Screenshot Generator",
      "description": "Capture clean screenshots of public X posts, threads and profiles without login. Choose post cards, contiguous threads, profile headers or profile previews, dark/light theme, PNG/JPEG/WEBP output and real 2x/3x pixel density.",
      "seoTitle": "Twitter Screenshot Generator — X Post & Profile Captures",
      "seoDescription": "Capture clean screenshots of public X (Twitter) posts and profiles without login. Post cards or full profiles, dark/light theme, PNG/JPEG/WEBP and retina-quality output.",
      "version": "1.0",
      "buildTag": "latest",
      "dockerfile": "./Dockerfile",
      "readme": "# Twitter (X) Screenshot Generator\r\n\r\nCapture clean screenshots of public X posts, threads and profiles — **no login, no cookies, no API key**. Paste post links to get pixel-perfect post cards or a contiguous thread image, or profile links to get the profile header or the loaded profile preview. Choose dark, light or system theme, PNG/JPEG/WEBP output, and 1x–3x pixel density. Capture dark and light in one run, and optionally save a verifiable evidence pack (gzipped DOM snapshot + JSON manifest with SHA-256 hashes).\r\n\r\n## What this actor does\r\n\r\n- **Four capture modes:** `postCard` (one post), `thread` (root post + contiguous same-author replies), `profileHeader` (header only) and `fullProfilePage` (the loaded profile preview)\r\n- **Verified targets:** the canonical post id and author handle are checked, so a short ID that resolves to another author is reported as `wrong_author` instead of a false success\r\n- **Honest failure states:** protected, deleted, missing and login-walled pages return typed, non-billable status rows\r\n- **Clean captures:** headers, sidebars, login prompts, the late \"Continue to X\" gate, sticky top bars, video player chrome and community notes are hidden automatically; the overlay hide is repeated after a 2.5s settle\r\n- **Image control:** PNG, JPEG or WEBP, quality setting for JPEG/WEBP, and real 1x/2x/3x pixel density with `effectiveScale` reported\r\n- **Custom viewport:** width and height from 320×240 up to 3840×2160\r\n- **Optional details:** post ID, URL, author handle, text snippet, and profile or author follower counts when X shows them\r\n- **Both themes in one run:** `bothThemes` captures dark and light versions with unique files and one row per theme\r\n- **Evidence pack:** `includeEvidence` saves a gzipped DOM snapshot and a JSON manifest to the key-value store, and reports `screenshotSha256`, `domSnapshotSha256`, `evidenceKey` and `manifestKey` on each row\r\n- **Empty fields are omitted:** never null, empty strings or empty arrays/objects.\r\n- **Run summary:** one `runSummary` row reports requested/captured/failed/billable counts, typed failure codes and dropped inputs\r\n- **Empty fields are omitted**\r\n\r\n## Output per screenshot\r\n\r\nEach row has a `type`: `screenshot` for a capture, `status` for a failure/run message, or `runSummary` for the end-of-run totals. If no post or profile link was provided at all, a single `status` row with `status: \"noInput\"` is emitted plus the summary; unsupported inputs are reported in `invalidInputs`.\r\n\r\n| Field | Description |\r\n|---|---|\r\n| `targetUrl` | The canonical post or profile URL that was captured (the requested URL on failures) |\r\n| `targetType` | `post` or `profile` |\r\n| `captureMode` | `postCard`, `thread`, `profileHeader` or `fullProfilePage` |\r\n| `status` | `success` or a friendly error description |\r\n| `code` | Typed failure code: `not_found`, `protected`, `deleted`, `login_wall`, `wrong_author`, `wrong_target`, `selector_miss`, `media_error`, `browser_crash`, `network_error`, `invalid_input` or `capture_error` |\r\n| `billable` | `true` only for captured screenshot rows |\r\n| `accessState` | `public`, `protected`, `deleted`, `not_found` or `login_wall` |\r\n| `requestedUrl`, `canonicalUrl` | The input URL and the canonical URL X served |\r\n| `width`, `height` | Dimensions of the captured image in pixels |\r\n| `format` | Saved image format (`png`, `jpeg` or `webp`) |\r\n| `fileSizeBytes` | Size of the saved image |\r\n| `filename` | File name in the key-value store, including mode/theme/format/DPR |\r\n| `downloadUrl` | Public signed HTTPS link to download the image (omitted when signing fails or only a local `file://` URL exists) |\r\n| `quality` | JPEG/WEBP quality setting used |\r\n| `deviceScaleFactor` | Pixel density used for the capture (1, 2 or 3) |\r\n| `effectiveScale` | Actual image pixels per CSS pixel |\r\n| `previewLimited`, `previewLimitReason` | Profile preview cap flags |\r\n| `thread` | Thread parts, length, gate position, completion and truncation reason (`thread` mode) |\r\n| `poll` | Poll choices with percentages and, when syndication is reachable, exact vote counts (`includeMetadata` only) |\r\n| `communityNote` | Readers-added-context id and text (`includeMetadata` only) |\r\n| `capturedAt`, `collectedAt`, `scrapedAt` | ISO timestamps of the capture |\r\n| `recordType` | `screenshot`, `status` or `runSummary` |\r\n| `sourceUrl` | Canonical target URL (`targetUrl`) when one exists |\r\n| `profileUrl` | The profile URL, on profile captures |\r\n| `theme` | The theme captured in this row (`dark` or `light`) |\r\n| `screenshotSha256` | SHA-256 of the saved image bytes (`includeEvidence` only) |\r\n| `domSnapshotSha256` | SHA-256 of the raw DOM snapshot before gzip (`includeEvidence` only) |\r\n| `evidenceKey` | Key-value store key of the gzipped DOM snapshot (`includeEvidence` only) |\r\n| `manifestKey` | Key-value store key of the JSON evidence manifest (`includeEvidence` only) |\r\n\r\nThe `runSummary` row contains `requested`, `captured`, `failed`, `skipped`, `billable`, `billableScreenshots`, `failureCodes`, `invalidInputs`, `theme`, `themes`, `format`, `deviceScaleFactor`, `captureMode`, `totalBytes`, `totalDurationMs`, `startedAt` and `finishedAt`. With **Both themes** on, `requested`/`captured` count both theme captures and `themes` is `[\"dark\", \"light\"]`.\r\n\r\nWith **Include post/profile details** on, post rows also carry `tweetId`, `tweetUrl`, `authorUsername`, `textSnippet`, `poll`, `communityNote`, `authorFollowers`, `authorFollowing` and `authorPostCount`; profile rows carry `username`, `name`, `followers`, `following` and `postCount`. Counts and poll/note fields are only added when X shows them.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `postUrls` | array | – | Post links, bare post IDs, profile links or bare usernames |\r\n| `tweetUrls` | array | – | Alias of post links |\r\n| `profileUrls` | array | – | Profiles to capture (header or full page, depending on capture mode) |\r\n| `captureMode` | string | `postCard` | `postCard`, `thread`, `profileHeader` or `fullProfilePage`. In profile modes, post links capture the post's author profile instead |\r\n| `theme` | string | `dark` | `dark`, `light` or `system` |\r\n| `bothThemes` | boolean | `false` | Capture dark and light versions of every target in one run; one row per theme and unique files |\r\n| `includeEvidence` | boolean | `false` | Save a gzipped DOM snapshot and JSON manifest to the key-value store and add SHA-256/evidence fields to rows |\r\n| `fullPage` | boolean | `false` | Capture the clipped post/profile column instead of just the card or header |\r\n| `hideReplies` | boolean | `true` | Hide reply posts so captures stay focused (ignored in `thread` mode, which keeps contiguous author parts) |\r\n| `includeMetadata` | boolean | `false` | Add post/profile details and counts to each row |\r\n| `format` | string | `png` | `png` (lossless), `jpeg` or `webp` |\r\n| `quality` | integer | `90` | Quality for JPEG/WEBP (1–100); ignored for PNG |\r\n| `deviceScaleFactor` | string | `1x` | `1x`, `2x` or `3x` pixel density reported as `effectiveScale` |\r\n| `viewportWidth` | integer | `1440` | Browser width used for the capture (320–3840) |\r\n| `viewportHeight` | integer | `900` | Browser height used for the capture (240–2160) |\r\n| `maxThreadHeight` | integer | `8000` | Maximum thread image height; taller threads are clipped and marked incomplete |\r\n| `proxyConfiguration` | object | – | Optional, for large or repeated runs |\r\n\r\nAt least one post link or profile link is required. Any input works in any list — links, IDs and usernames are routed automatically.\r\n\r\n### Example: post card\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"https://x.com/NASA/status/2107095768821576019\"],\r\n  \"theme\": \"dark\",\r\n  \"hideReplies\": true,\r\n  \"includeMetadata\": true\r\n}\r\n```\r\n\r\n### Example: thread\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"https://x.com/naval/status/1002103360646823936\"],\r\n  \"captureMode\": \"thread\",\r\n  \"maxThreadHeight\": 8000,\r\n  \"theme\": \"dark\",\r\n  \"includeMetadata\": true\r\n}\r\n```\r\n\r\n### Example: profile header\r\n\r\n```json\r\n{\r\n  \"profileUrls\": [\"https://x.com/apify\"],\r\n  \"captureMode\": \"profileHeader\",\r\n  \"theme\": \"light\",\r\n  \"viewportWidth\": 1280,\r\n  \"viewportHeight\": 800\r\n}\r\n```\r\n\r\n### Example: full profile page\r\n\r\n```json\r\n{\r\n  \"profileUrls\": [\"apify\"],\r\n  \"captureMode\": \"fullProfilePage\",\r\n  \"fullPage\": true\r\n}\r\n```\r\n\r\n### Example: high-density JPEG\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"2107095768821576019\"],\r\n  \"format\": \"jpeg\",\r\n  \"quality\": 85,\r\n  \"deviceScaleFactor\": \"2x\"\r\n}\r\n```\r\n\r\n### Example: both themes + evidence pack\r\n\r\n```json\r\n{\r\n  \"postUrls\": [\"https://x.com/NASA/status/2107095768821576019\"],\r\n  \"bothThemes\": true,\r\n  \"includeEvidence\": true,\r\n  \"includeMetadata\": true\r\n}\r\n```\r\n\r\nThis produces two screenshot rows (`theme: \"dark\"` and `theme: \"light\"`), each with its own image, `screenshotSha256`, `domSnapshotSha256`, `evidenceKey` and `manifestKey`. The evidence files live in the same key-value store as the images.\r\n\r\n### Example record\r\n\r\n```json\r\n{\r\n  \"type\": \"screenshot\",\r\n  \"targetUrl\": \"https://x.com/NASA/status/2107095768821576019\",\r\n  \"targetType\": \"post\",\r\n  \"captureMode\": \"postCard\",\r\n  \"theme\": \"dark\",\r\n  \"status\": \"success\",\r\n  \"width\": 1440,\r\n  \"height\": 810,\r\n  \"format\": \"png\",\r\n  \"fileSizeBytes\": 412345,\r\n  \"filename\": \"screenshot_2107095768821576019_postcard_dark_png_1x.png\",\r\n  \"downloadUrl\": \"https://api.apify.com/v2/key-value-stores/{STORE_ID}/records/screenshot_2107095768821576019_postcard_dark_png_1x.png?signature=...\",\r\n  \"deviceScaleFactor\": 1,\r\n  \"screenshotSha256\": \"5f2b...\",\r\n  \"domSnapshotSha256\": \"a91c...\",\r\n  \"evidenceKey\": \"evidence_screenshot_2107095768821576019_postcard_dark_png_1x.html.gz\",\r\n  \"manifestKey\": \"manifest_screenshot_2107095768821576019_postcard_dark_png_1x.json\",\r\n  \"capturedAt\": \"2026-10-06T10:30:00+00:00\",\r\n  \"tweetId\": \"2107095768821576019\",\r\n  \"tweetUrl\": \"https://x.com/NASA/status/2107095768821576019\",\r\n  \"authorUsername\": \"NASA\",\r\n  \"textSnippet\": \"It's World Space Week! ...\"\r\n}\r\n```\r\n\r\n## Limits\r\n\r\n- Public content only — protected accounts return a `protected` status row and cannot be captured.\r\n- Logged-out profiles show a loaded preview of roughly 5–10 posts (observed 5–10; it never grows with scrolling). `fullProfilePage` is that preview, not the infinite timeline, and rows set `previewLimited: true`. `profileHeader` is header-only by design.\r\n- Logged-out post pages render only the first ~4–10 replies. The `See all the replies / Continue to X` gate appears after scrolling; `/replies` is a 404/login redirect for guests, so deeper reply paging is not available.\r\n- Thread captures only contain the articles X renders in the logged-out DOM. A gate is reported as truncation only when its DOM position is before or inside the last captured part; a gate appended after the last article is the normal end of the preview. Non-author replies stop the contiguous block. Full unroll is not guaranteed.\r\n- `maxThreadHeight` is expressed in CSS pixels and is clamped automatically so the DPR-scaled image cannot exceed the 32,767 px screenshot ceiling (32,767 / 16,383 / 10,922 CSS px at 1x/2x/3x). Clipped threads report `threadComplete: false` with `truncatedReason: max_height` or `dpr_height_limit`.\r\n- Poll metadata is limited to the choices X renders or syndication binds (2–4 choices). Quote counts, places, full follower lists and sensitive flags are not available cookieless.\r\n- Community-note text is captured as text; the note is hidden from the image. The note id is included when the syndication/DOM link exposes it.\r\n- A bare short post ID can collide with an older post id. When the requested handle does not match the canonical author, the row fails with `wrong_author` rather than capturing the wrong post.\r\n- Metadata counts, poll and community-note fields are added only when X displays them.\r\n- Capture failures (for example a deleted post) produce a typed `status` row plus a `runSummary`, so a run is never silently empty or billed as a success.\r\n- **Both themes** doubles runtime, screenshots and dataset rows; files and evidence keys remain unique per theme.\r\n- **Include evidence pack** adds the DOM snapshot (gzipped, typically ~7% of the screenshot size) and a manifest per capture. The DOM is the post-hide rendered markup, not the raw HTTP response.\r\n- Evidence manifests are still written for failed captures (with `failure.code`, `failure.message` and `failure.accessState`) when the page is available; a crashed page may leave only the manifest.\r\n## Use cases\r\n\r\n- **Social media reporting** — embed clean post captures in decks, newsletters and blogs\r\n- **Brand monitoring** — archive screenshots of public posts as evidence\r\n- **Community management** — capture profile pages for creator or partner reviews\r\n- **Research** — build image datasets of public posts with consistent framing and theme\r\n- **Content creation** — generate post images for roundups without manual screenshotting\r\n- **Legal and compliance** — timestamped captures of public posts with source URLs, SHA-256 hashes and a DOM snapshot as an evidence trail\r\n\r\n## FAQ\r\n\r\n**Can I screenshot private accounts or posts?** No. Only public posts and profiles are accessible.\r\n\r\n**What resolution are the screenshots?** The viewport defaults to 1440×900 and is configurable from 320×240 up to 3840×2160. With `2x` or `3x` pixel density the saved image is two or three times larger on each side. The actual dimensions are always reported in `width` and `height`.\r\n\r\n**What is the difference between the capture modes?** `postCard` captures a single post as a clean card; `profileHeader` captures only the profile header (banner, avatar, name, bio, counts and tabs); `fullProfilePage` captures the loaded profile preview with its posts; `thread` captures the root post plus contiguous same-author replies. A post link captures a post card only in `postCard` mode — if `profileHeader` or `fullProfilePage` is selected, a post link captures that post's author profile instead.\r\n\r\n**Does it support threads?** Yes. Set `captureMode` to `thread` and the actor captures the root post plus the contiguous same-author replies as one image. Threads that hit a logged-out gate, a different author or `maxThreadHeight` are marked `threadComplete: false` with a truncation reason. The logged-out page only contains the articles X renders, so full unroll is not guaranteed.\r\n\r\n**What happens if a post contains a video?** The actor waits for the video to decode, pauses it, seeks to a representative frame, hides the player controls and applies a luma/poster guard against black frames before capturing.\r\n\r\n**What gets hidden in a capture?** The left navigation, headers, sidebars, login prompts, the late \"Continue to X\" gate, sticky top bars, video controls, empty fixed overlays and community notes are hidden automatically. The hide runs repeatedly after a 2.5s settle. Reply posts are hidden when **Hide replies** is on.\r\n\r\n**Which image format should I use?** PNG for lossless quality, JPEG for smaller files, WEBP for the smallest files. JPEG and WEBP use the quality setting.\r\n\r\n**What if a link is invalid or the post was deleted?** The row gets a typed `code` and a friendly `status` instead of a screenshot, marked `billable: false`. Protected, deleted, missing and login-walled pages are detected before the selector timeouts, and the run never crashes. The final `runSummary` row lists the counts and reasons.\r\n\r\n**Can I capture dark and light in one run?** Yes. Turn on **Both themes** and every target is captured twice, once dark and once light. Files include the theme in the name, so nothing is overwritten, and each theme gets its own dataset row and `theme` value. The run summary counts both captures and lists `themes: [\"dark\", \"light\"]`.\r\n\r\n**What is the evidence pack?** With **Include evidence pack** on, each capture also writes `evidence_<key>.html.gz` (the rendered DOM, gzipped) and `manifest_<key>.json` (target, capture metadata, dimensions, SHA-256 hashes, and failure state when the capture failed) to the key-value store. Rows get `screenshotSha256`, `domSnapshotSha256`, `evidenceKey` and `manifestKey`. Evidence is typically ~7% of the screenshot size; failures still get a manifest even when no image was produced.\r\n\r\n**How long do download links last?** They follow your Apify key-value store retention (typically 7 days on the free tier). Copy the images to your own storage for permanent archival.\r\n\r\n**Is this affiliated with X?** No. This is a third-party actor that captures publicly visible pages.\r\n\r\n",
      "input": {
        "title": "Twitter (X) Screenshot Generator",
        "description": "Capture clean PNG screenshots of public X posts and profiles. No login or cookies required.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "postUrls": {
            "title": "X post links, IDs or usernames",
            "type": "array",
            "description": "Posts to capture as clean post cards. Paste x.com or twitter.com links, bare numeric post IDs, profile links or bare usernames. Any input works in every list.",
            "editor": "stringList",
            "prefill": [
              "https://x.com/NASA/status/2107095768821576019"
            ],
            "default": []
          },
          "tweetUrls": {
            "title": "Tweet links (alias)",
            "type": "array",
            "description": "Alias of X post links. Accepts tweet links, bare tweet IDs, profile links and bare usernames.",
            "editor": "stringList",
            "default": []
          },
          "profileUrls": {
            "title": "X profile links or usernames",
            "type": "array",
            "description": "Optional. Profiles to capture. Paste profile links, bare usernames, post links or post IDs and the actor routes them to the right capture. Use capture mode to choose the header only or the loaded profile preview.",
            "editor": "stringList",
            "default": []
          },
          "captureMode": {
            "title": "Capture mode",
            "type": "string",
            "description": "What to capture. Post links produce a single post card or a thread image; profile modes apply to profile links (and convert post links to the author profile).",
            "editor": "select",
            "enum": [
              "postCard",
              "thread",
              "profileHeader",
              "fullProfilePage"
            ],
            "enumTitles": [
              "Post card (one post)",
              "Thread (root + contiguous author replies)",
              "Profile header (header only)",
              "Full profile page (loaded preview)"
            ],
            "default": "postCard",
            "prefill": "postCard"
          },
          "theme": {
            "title": "Theme",
            "type": "string",
            "description": "Color theme for the screenshot.",
            "editor": "select",
            "enum": [
              "dark",
              "light",
              "system"
            ],
            "enumTitles": [
              "Dark",
              "Light",
              "System (browser default)"
            ],
            "default": "dark",
            "prefill": "dark"
          },
          "bothThemes": {
            "title": "Both themes",
            "type": "boolean",
            "description": "When on, every target is captured twice: once in dark and once in light. Files and rows are unique per theme (one screenshot row per theme) and the run summary reports both themes. Overrides the Theme selection.",
            "default": false,
            "prefill": false
          },
          "includeEvidence": {
            "title": "Include evidence pack",
            "type": "boolean",
            "description": "Save a gzipped DOM snapshot and a JSON manifest to the key-value store for every capture, and add screenshotSha256, domSnapshotSha256, evidenceKey and manifestKey to each row. Failures still get a manifest with the typed failure state.",
            "default": false,
            "prefill": false
          },
          "fullPage": {
            "title": "Full-page capture",
            "type": "boolean",
            "description": "When on, the whole page is captured instead of just the post card or the visible profile header.",
            "default": false,
            "prefill": false
          },
          "hideReplies": {
            "title": "Hide replies",
            "type": "boolean",
            "description": "Hide reply posts so screenshots stay focused on original posts.",
            "default": true,
            "prefill": true
          },
          "includeMetadata": {
            "title": "Include post/profile details",
            "type": "boolean",
            "description": "Add details to each row: post id, post URL, author handle, text snippet and the author's follower, following and post counts for posts; username, display name, follower, following and post counts for profiles. Counts are only added when X shows them.",
            "default": false,
            "prefill": false
          },
          "format": {
            "title": "Image format",
            "type": "string",
            "description": "File format of the saved screenshot. JPEG and WEBP support the quality setting; PNG is lossless.",
            "editor": "select",
            "enum": [
              "png",
              "jpeg",
              "webp"
            ],
            "enumTitles": [
              "PNG (lossless, largest)",
              "JPEG (smaller file, quality setting applies)",
              "WEBP (smallest file, quality setting applies)"
            ],
            "default": "png",
            "prefill": "png"
          },
          "quality": {
            "title": "Image quality",
            "type": "integer",
            "description": "Quality for JPEG and WEBP output (1-100). Ignored for PNG.",
            "default": 90,
            "prefill": 90,
            "minimum": 1,
            "maximum": 100
          },
          "deviceScaleFactor": {
            "title": "Pixel density",
            "type": "string",
            "description": "Render the page at a higher pixel density for sharper screenshots. 2x doubles and 3x triples the pixel dimensions.",
            "editor": "select",
            "enum": [
              "1x",
              "2x",
              "3x"
            ],
            "enumTitles": [
              "1x (standard)",
              "2x (retina)",
              "3x (high density)"
            ],
            "default": "1x",
            "prefill": "1x"
          },
          "viewportWidth": {
            "title": "Viewport width (pixels)",
            "type": "integer",
            "description": "Browser width used for the capture. Higher values fit more of the page.",
            "default": 1440,
            "minimum": 320,
            "maximum": 3840
          },
          "viewportHeight": {
            "title": "Viewport height (pixels)",
            "type": "integer",
            "description": "Browser height used for the capture.",
            "default": 900,
            "minimum": 240,
            "maximum": 2160
          },
          "maxThreadHeight": {
            "title": "Max thread height (px)",
            "type": "integer",
            "description": "Maximum thread column height in CSS pixels; the saved image is DPR times taller. The value is clamped so the image cannot exceed the 32,767 px screenshot ceiling (10,922 CSS px at 3x). Taller threads are clipped and the row reports threadComplete=false with the truncation reason.",
            "default": 8000,
            "prefill": 8000,
            "minimum": 500,
            "maximum": 20000,
            "sectionCaption": "Advanced",
            "sectionDescription": "Optional settings for large or repeated runs."
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Optional. Use a proxy if you plan large runs or see frequent rate limits.",
            "editor": "proxy",
            "nullable": true
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Twitter (X) Screenshot Generator Output",
        "description": "Screenshot capture records for public X posts and profiles, with image dimensions, format, and download link, plus the saved image files.",
        "type": "object",
        "properties": {
          "screenshots": {
            "type": "string",
            "title": "Screenshot results",
            "description": "Dataset with one row per captured post or profile",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          },
          "screenshotFiles": {
            "type": "string",
            "title": "Screenshot image files",
            "description": "Key-value store containing the screenshot image files",
            "template": "{{links.apiDefaultKeyValueStoreUrl}}/records"
          },
          "evidenceFiles": {
            "type": "string",
            "title": "Evidence files",
            "description": "Key-value store containing the gzipped DOM snapshots and JSON manifests when Include evidence pack is on",
            "template": "{{links.apiDefaultKeyValueStoreUrl}}/records"
          }
        }
      },
      "categories": [
        "SOCIAL_MEDIA"
      ],
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "title": "Twitter Screenshots",
          "views": {
            "overview": {
              "title": "Screenshots",
              "description": "Screenshots of Twitter/X posts and profiles with download links.",
              "transformation": {
                "fields": [
                  "type",
                  "targetUrl",
                  "captureMode",
                  "theme",
                  "status",
                  "code",
                  "billable",
                  "format",
                  "width",
                  "height",
                  "fileSizeBytes",
                  "filename",
                  "downloadUrl",
                  "capturedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "type": {
                    "label": "Row Type",
                    "format": "text"
                  },
                  "targetUrl": {
                    "label": "Target URL",
                    "format": "link"
                  },
                  "captureMode": {
                    "label": "Mode",
                    "format": "text"
                  },
                  "theme": {
                    "label": "Theme",
                    "format": "text"
                  },
                  "status": {
                    "label": "Status",
                    "format": "text"
                  },
                  "code": {
                    "label": "Code",
                    "format": "text"
                  },
                  "billable": {
                    "label": "Billable",
                    "format": "text"
                  },
                  "format": {
                    "label": "Format",
                    "format": "text"
                  },
                  "width": {
                    "label": "Width",
                    "format": "number"
                  },
                  "height": {
                    "label": "Height",
                    "format": "number"
                  },
                  "fileSizeBytes": {
                    "label": "Bytes",
                    "format": "number"
                  },
                  "filename": {
                    "label": "File",
                    "format": "text"
                  },
                  "downloadUrl": {
                    "label": "Download",
                    "format": "link"
                  },
                  "capturedAt": {
                    "label": "Captured At",
                    "format": "date"
                  }
                }
              }
            }
          },
          "fields": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "title": "Row type",
                "description": "screenshot for a captured image, status for a failure/run message, runSummary for end-of-run totals."
              },
              "targetUrl": {
                "type": "string",
                "title": "Target URL",
                "description": "The Twitter/X post or profile URL that was captured",
                "format": "link"
              },
              "profileUrl": {
                "type": "string",
                "title": "Profile URL",
                "description": "The profile URL when a profile was captured",
                "format": "link"
              },
              "captureMode": {
                "type": "string",
                "title": "Capture mode",
                "description": "postCard, thread, profileHeader (header only) or fullProfilePage (loaded preview)"
              },
              "status": {
                "type": "string",
                "title": "Status",
                "description": "Result status (success or a friendly error description)"
              },
              "code": {
                "type": "string",
                "title": "Status code",
                "description": "Typed failure code: not_found, protected, deleted, login_wall, wrong_author, wrong_target, selector_miss, media_error, browser_crash, network_error, invalid_input or capture_error"
              },
              "message": {
                "type": "string",
                "title": "Message",
                "description": "Human-readable failure message"
              },
              "billable": {
                "type": "boolean",
                "title": "Billable",
                "description": "True only for captured screenshot rows; status and summary rows are not billable"
              },
              "accessState": {
                "type": "string",
                "title": "Access state",
                "description": "public, protected, deleted, not_found or login_wall"
              },
              "requestedUrl": {
                "type": "string",
                "title": "Requested URL",
                "description": "The input URL as requested, when the canonical URL differs",
                "format": "link"
              },
              "canonicalUrl": {
                "type": "string",
                "title": "Canonical URL",
                "description": "The canonical X URL X actually served",
                "format": "link"
              },
              "effectiveScale": {
                "type": "number",
                "title": "Effective scale",
                "description": "Actual image pixels per CSS pixel (image width / clipped CSS width)"
              },
              "previewLimited": {
                "type": "boolean",
                "title": "Preview limited",
                "description": "True when a profile capture hit the logged-out preview cap"
              },
              "previewLimitReason": {
                "type": "string",
                "title": "Preview limit reason",
                "description": "Why the profile capture is a preview rather than the full timeline"
              },
              "thread": {
                "type": "object",
                "title": "Thread",
                "description": "Thread capture details: focalIndex, threadAuthor, threadLength, threadParts, gateIndex, threadComplete, truncatedReason (non_author_reply, gate, max_height, dpr_height_limit or no_parts)"
              },
              "threadId": {
                "type": "string",
                "title": "Thread ID",
                "description": "Focal post id for a thread capture"
              },
              "capturedPostCount": {
                "type": "number",
                "title": "Captured posts",
                "description": "Posts rendered in the profile capture"
              },
              "profilePostCount": {
                "type": "number",
                "title": "Profile posts",
                "description": "Post count shown in the profile header"
              },
              "requested": {
                "type": "number",
                "title": "Requested (run summary)",
                "description": "Targets requested in the run"
              },
              "captured": {
                "type": "number",
                "title": "Captured (run summary)",
                "description": "Screenshots captured in the run"
              },
              "failed": {
                "type": "number",
                "title": "Failed (run summary)",
                "description": "Targets that failed with a typed status code"
              },
              "skipped": {
                "type": "number",
                "title": "Skipped (run summary)",
                "description": "Inputs dropped during validation"
              },
              "billableScreenshots": {
                "type": "number",
                "title": "Billable screenshots (run summary)",
                "description": "Number of captured, billable screenshots in the run"
              },
              "failureCodes": {
                "type": "object",
                "title": "Failure codes (run summary)",
                "description": "Count of each typed failure code"
              },
              "invalidInputs": {
                "type": "array",
                "title": "Invalid inputs (run summary)",
                "description": "Inputs dropped during validation with a reason"
              },
              "totalBytes": {
                "type": "number",
                "title": "Total bytes (run summary)",
                "description": "Combined size of all captured images"
              },
              "width": {
                "type": "number",
                "title": "Width",
                "description": "Width of the captured image in pixels"
              },
              "height": {
                "type": "number",
                "title": "Height",
                "description": "Height of the captured image in pixels"
              },
              "filename": {
                "type": "string",
                "title": "File name",
                "description": "File name of the screenshot in the key-value store"
              },
              "downloadUrl": {
                "type": "string",
                "title": "Download URL",
                "description": "Public signed HTTPS URL to download the screenshot file (omitted for local file:// URLs and when signing fails)",
                "format": "link"
              },
              "capturedAt": {
                "type": "string",
                "title": "Captured at",
                "description": "ISO timestamp when the screenshot was taken"
              },
              "tweetId": {
                "type": "string",
                "title": "Post ID",
                "description": "Numeric post id (when Include post/profile details is on)"
              },
              "tweetUrl": {
                "type": "string",
                "title": "Post URL",
                "description": "Canonical post URL (when Include post/profile details is on)"
              },
              "authorUsername": {
                "type": "string",
                "title": "Author",
                "description": "Post author handle (when Include post/profile details is on)"
              },
              "textSnippet": {
                "type": "string",
                "title": "Text snippet",
                "description": "First characters of the post text (when Include post/profile details is on)"
              },
              "poll": {
                "type": "object",
                "title": "Poll",
                "description": "Poll choices, percentages, vote total and finality when X renders or syndicates poll data (when Include post/profile details is on)"
              },
              "communityNote": {
                "type": "object",
                "title": "Community note",
                "description": "Readers-added-context note id and text when X shows one (when Include post/profile details is on)"
              },
              "username": {
                "type": "string",
                "title": "Profile username",
                "description": "Profile handle (when Include post/profile details is on)"
              },
              "name": {
                "type": "string",
                "title": "Profile name",
                "description": "Profile display name (when Include post/profile details is on)"
              },
              "followers": {
                "type": "number",
                "title": "Followers",
                "description": "Follower count (when Include post/profile details is on)"
              },
              "following": {
                "type": "number",
                "title": "Following",
                "description": "Accounts followed (when Include post/profile details is on)"
              },
              "postCount": {
                "type": "number",
                "title": "Posts",
                "description": "Profile post count (when Include post/profile details is on)"
              },
              "authorFollowers": {
                "type": "number",
                "title": "Author followers",
                "description": "Post author follower count (when Include post/profile details is on)"
              },
              "authorFollowing": {
                "type": "number",
                "title": "Author following",
                "description": "Post author following count (when Include post/profile details is on)"
              },
              "authorPostCount": {
                "type": "number",
                "title": "Author posts",
                "description": "Post author post count (when Include post/profile details is on)"
              },
              "format": {
                "type": "string",
                "title": "Format",
                "description": "Saved image format (png, jpeg or webp)"
              },
              "quality": {
                "type": "number",
                "title": "Quality",
                "description": "JPEG/WEBP quality setting"
              },
              "fileSizeBytes": {
                "type": "number",
                "title": "File size",
                "description": "Size of the saved screenshot in bytes"
              },
              "deviceScaleFactor": {
                "type": "number",
                "title": "Pixel density",
                "description": "Device scale factor used for the capture (effective value)"
              },
              "theme": {
                "type": "string",
                "title": "Theme",
                "description": "dark, light or system (the captured theme on each row)"
              },
              "themes": {
                "type": "array",
                "title": "Themes (run summary)",
                "description": "Themes captured in the run; both dark and light when Both themes is on",
                "items": {
                  "type": "string"
                }
              },
              "screenshotSha256": {
                "type": "string",
                "title": "Screenshot SHA-256",
                "description": "SHA-256 of the saved screenshot bytes (when Include evidence pack is on)"
              },
              "domSnapshotSha256": {
                "type": "string",
                "title": "DOM snapshot SHA-256",
                "description": "SHA-256 of the raw DOM snapshot before gzip (when Include evidence pack is on)"
              },
              "evidenceKey": {
                "type": "string",
                "title": "Evidence key",
                "description": "Key-value store key of the gzipped DOM snapshot (when Include evidence pack is on)"
              },
              "manifestKey": {
                "type": "string",
                "title": "Manifest key",
                "description": "Key-value store key of the JSON evidence manifest (when Include evidence pack is on)"
              },
              "evidenceError": {
                "type": "string",
                "title": "Evidence error",
                "description": "Why the evidence files could not be written, when Include evidence pack is on"
              },
              "totalDurationMs": {
                "type": "number",
                "title": "Duration (run summary)",
                "description": "Total capture duration in milliseconds"
              },
              "startedAt": {
                "type": "string",
                "title": "Started at (run summary)",
                "description": "ISO timestamp when the run started"
              },
              "finishedAt": {
                "type": "string",
                "title": "Finished at (run summary)",
                "description": "ISO timestamp when the run finished"
              }
            }
          }
        }
      },
      "defaultRunOptions": {
        "build": "latest",
        "timeoutSecs": 3600,
        "memoryMbytes": 4096
      }
    },
    "buildNumber": "1.0.6",
    "imageDigest": "3f455715378b95e6e113b25473ef777a2fbc8414f75f8540a9a0579908db9255",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.01099888888888889
    }
  }
}