{
  "openapi": "3.0.1",
  "info": {
    "title": "Mastodon Scraper - Trending Profiles, Posts & Replies",
    "description": "Scrape trending Mastodon profiles and related posts from any Mastodon instance. Extract usernames, bios, follower counts, avatars, profile fields, posts and thread replies. Supports nested profile reviews or flat review output for easier analysis.",
    "version": "1.0",
    "x-build-id": "D2UHSuBvWV0vufMBc"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~mastodon-social-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-mastodon-social-scraper",
        "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/abotapi~mastodon-social-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-mastodon-social-scraper",
        "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/abotapi~mastodon-social-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-mastodon-social-scraper",
        "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": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Output mode",
            "enum": [
              "profiles",
              "reviews",
              "keyword",
              "urls"
            ],
            "type": "string",
            "description": "What the actor returns. 'profiles' = one record per trending profile with its reviews nested inside. 'reviews' = one flat record per review (a post or a reply). 'keyword' = bulk posts for the keywords you list, one flat record per post, walked via load-more pagination (the high-volume option). 'urls' = scrape exactly the URLs listed in the URLs field (profiles output).",
            "default": "profiles"
          },
          "instanceUrl": {
            "title": "Mastodon instance",
            "type": "string",
            "description": "Which Mastodon server to read the explore page from. Defaults to mastodon.social. Any public Mastodon instance works (for example https://mas.to or https://fosstodon.org).",
            "default": "https://mastodon.social"
          },
          "profileSource": {
            "title": "Trending profile source",
            "enum": [
              "trending",
              "directory",
              "both"
            ],
            "type": "string",
            "description": "Where trending profiles come from. 'trending' = the authors of currently trending posts. 'directory' = the active public profile directory. 'both' = the two merged and deduped. Only applies when no URLs are provided.",
            "default": "both"
          },
          "onlyLocal": {
            "title": "Local accounts only",
            "type": "boolean",
            "description": "When using the directory source, return only accounts that are local to the chosen instance (skip federated accounts from other servers).",
            "default": false
          },
          "urls": {
            "title": "URLs (any Mastodon URL shape)",
            "type": "array",
            "description": "Mastodon URLs to scrape. Supported: profile (/@user, /@user/with_replies, /@user.rss, /users/user, /web/@user, other-instance /@user), post (/@user/ID, /@user/ID/embed, /users/user/statuses/ID, /web/statuses/ID), tag page (/tags/news), explore (/explore), profile directory (/directory), and the matching /api/v1 JSON URLs. Unsupported URLs are skipped with a warning. The prefilled list is one example per shape and runs as-is only when Output mode is 'Pasted URLs'; in other modes an unedited list is ignored, an edited list always applies.",
            "default": [
              "https://mastodon.social/explore",
              "https://mastodon.social/@Mastodon",
              "https://mastodon.social/@Mastodon/with_replies",
              "https://mastodon.social/@Mastodon/117466985005297414",
              "https://mastodon.social/tags/news",
              "https://mastodon.social/users/Mastodon",
              "https://mastodon.social/web/@Mastodon",
              "https://mastodon.social/@Mastodon.rss",
              "https://fosstodon.org/@fosstodon",
              "https://mastodon.social/directory",
              "https://mastodon.social/api/v1/accounts/lookup?acct=Mastodon",
              "https://mastodon.social/@Mastodon/with_replies?max_id=1",
              "https://mastodon.social/@Mastodon/117466983307949301/embed",
              "https://mastodon.social/users/Mastodon/statuses/117411420916699261",
              "https://mastodon.social/web/statuses/117156549508722805",
              "https://mastodon.social/explore/posts",
              "https://mastodon.social/api/v1/timelines/tag/fediverse?limit=2",
              "https://mastodon.social/api/v1/trends/statuses?limit=2",
              "https://mastodon.social/api/v1/directory?limit=2",
              "https://mastodon.social/api/v1/statuses/117128801091131239/context"
            ],
            "items": {
              "type": "string"
            }
          },
          "accounts": {
            "title": "Accounts (plain names)",
            "type": "array",
            "description": "Profile names to scrape, typed as people write them: Mastodon, @Mastodon, or user@other.instance. A leading @ is ignored. Names that do not resolve are skipped with a warning. Works in profiles and reviews modes.",
            "items": {
              "type": "string"
            }
          },
          "keywords": {
            "title": "Keywords (keyword mode)",
            "type": "array",
            "description": "Topics to bulk-scrape when mode is 'keyword'. Enter one word per entry, with or without a leading # (for example: news, art, climate). Each keyword is matched as a Mastodon tag and its public timeline is walked back via load-more pagination up to Max posts. Note: keywords match single tags, not free-text phrases (free-text search needs a token). A keyword with no matching posts is reported with a warning.",
            "items": {
              "type": "string"
            }
          },
          "hashtags": {
            "title": "Hashtags (alias of keywords)",
            "type": "array",
            "description": "Same as Keywords: tags to scrape without the # symbol (for example: opensource, linux). Merged with Keywords.",
            "items": {
              "type": "string"
            }
          },
          "includeReplies": {
            "title": "Include replies",
            "type": "boolean",
            "description": "Fetch the reply thread under each post. Replies are added as reviews of type 'reply'. Turning this off makes runs faster and cheaper (one fewer request per post).",
            "default": true
          },
          "includeBoosts": {
            "title": "Include boosts",
            "type": "boolean",
            "description": "Include posts the profile boosted (reblogged) from other accounts. Turn off to keep only the profile's own posts.",
            "default": true
          },
          "since": {
            "title": "Posts since (date)",
            "type": "string",
            "description": "Keep only posts created on or after this date (YYYY-MM-DD or ISO datetime). Applied to the posts fetched for each profile, pasted tag URL, keyword tag or pasted post URL, so raise Max posts / Max reviews per profile to reach back further. Example: 2026-01-01."
          },
          "until": {
            "title": "Posts until (date)",
            "type": "string",
            "description": "Keep only posts created on or before this date (YYYY-MM-DD includes that whole day, or ISO datetime). Applied to the fetched window like Posts since. Example: 2026-12-31."
          },
          "sortBy": {
            "title": "Sort posts by",
            "enum": [
              "newest",
              "oldest",
              "mostFavourited",
              "mostReblogged",
              "mostReplied"
            ],
            "type": "string",
            "description": "Order of posts within each profile or tag: newest (default, platform order), oldest, most favourited, most reblogged or most replied. Sorting applies to the fetched window, not the whole history.",
            "default": "newest"
          },
          "maxProfiles": {
            "title": "Max profiles",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Maximum number of trending or directory profiles to scrape (profiles mode, or as review sources in reviews mode). Also caps how many recent posts are fetched from each pasted tag URL (/tags/NAME) and from each pasted explore or directory URL.",
            "default": 10
          },
          "maxReviewsPerProfile": {
            "title": "Max posts per profile",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "How many of each profile's most recent posts to fetch. The profile timeline is walked back via load-more pagination, so you can pull deep history (up to 5000). Each post may also bring its replies (see Include replies).",
            "default": 5
          },
          "maxRepliesPerPost": {
            "title": "Max replies per post",
            "minimum": 0,
            "maximum": 200,
            "type": "integer",
            "description": "Cap on how many replies to keep per post when Include replies is on.",
            "default": 10
          },
          "maxReviews": {
            "title": "Max reviews (reviews mode)",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Hard cap on total reviews returned in reviews mode (maximum 100000). 0 (older saved tasks) is treated as the default of 1000.",
            "default": 1000
          },
          "maxPosts": {
            "title": "Max posts (keyword mode)",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "Hard cap on total posts returned in keyword mode, split evenly across the keywords you list. Each keyword timeline is walked via load-more until this many posts are collected.",
            "default": 500
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Proxy settings. The default connection works on every Apify plan, including the free tier. A residential connection is optional and only needed for very large or sustained runs.",
            "default": {
              "useApifyProxy": true
            }
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue an interrupted crawl without returning or charging for records already collected there. Use this after an interrupted run. For recurring monitoring of the same search (daily/weekly), use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns everything as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED records. Compared: every profile field (bio, display name, avatar, counts, locked, fields) and every post field (text, media, tags, counts on a post record). Excluded from the comparison (still returned in the output): the engagement counters of posts nested inside a profile record, the embedded author's follower/following/post counters on a post record, list ordering, and any field you name in \"Ignore fields when detecting changes\". Replies never produce EXPIRED, and EXPIRED is only produced for pasted profile/post URL runs, account-list runs and keyword runs that reached the natural end of every scope, never for explore (trending/directory) discovery and never when a pasted explore, directory or tag URL is among the sources. Turn on \"Emit unchanged\" or \"Emit expired\" only when you also want those records returned (and billed). State is kept separately for each mode/instance/search/filter setup (including Accounts, Include boosts and the since/until dates); use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from mode, instance, and every query/filter setting — different searches then never mix state with each other."
          },
          "emitUnchanged": {
            "title": "Emit unchanged records (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired records (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked scope — not when a cap or Resume cut it short. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Optional. Field names that must NOT make a record UPDATED or appear in changedFields, for example bio or followersCount. A bare name applies to the record and to each post inside a profile's reviews list; use reviews.name to limit it to posts inside the list. Ignored fields are still returned in the output; they are only left out of the comparison.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com)."
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}