# Lemon8 Profile Scraper: Posts, Engagement, Comments & Media (`abotapi/lemon8-profile-scraper`) Actor

Scrape Lemon8 user profiles with automated multi-profile discovery. Extract profile data, detailed posts, engagement metrics, comments, and high-quality images and videos with download support. Built for influencer research, content analysis, and media archiving.

- **URL**: https://apify.com/abotapi/lemon8-profile-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Social media, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 69 total users, 8 monthly users, 81.5% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

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

## How to integrate an Actor?

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

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

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

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

# README

## Lemon8 Profile Scraper: Posts, Media, Engagement and Following Data

Lemon8 Profile Scraper turns any Lemon8 creator profile into structured data. Give it a username, a profile link, or a list of profile links, and get back every post's title, content, hashtags, images and comments, plus engagement counts, the creator's bio, follower and following numbers, and optionally the accounts they follow. Export the results to JSON, CSV or Excel, or pull them straight into your app through the API.

### Why This Scraper?

- **Three ways to target a profile.** Scrape one profile by username, paste a full profile link, or list many profile links at once. A clear precedence order means you always know which input wins.
- **Full post extraction.** Title, content, hashtags, publish date and, when Get Detailed Post Data is on, the complete comment thread with replies.
- **Profile context included.** Bio, follower and following counts, verification status and total post count come back with every profile, not just the posts.
- **Network mapping.** Turn on Scrape Following Profiles to also collect the accounts a creator follows.
- **Media on demand.** Optionally save every post's images and videos into the run's storage instead of only linking to them.
- **11 regions.** Scrape the US, Australia, Japan, the Philippines and seven other Lemon8 storefronts by changing one field.
- **Built for schedules.** Incremental mode returns only new and changed posts on recurring runs, Resume continues an interrupted pull without re-billing, and a refused run fails loudly instead of returning an empty dataset.

### Use Cases

- **Creator and influencer research:** track a profile's bio, follower growth and post cadence over time.
- **Content and trend analysis:** pull full post text, hashtags and images across a set of profiles to spot recurring topics.
- **Network mapping:** use Scrape Following Profiles to see who a creator follows and build an account graph.
- **Media archiving:** save every image and video attached to a profile's posts.
- **Recurring monitoring:** schedule incremental runs to catch new posts and edits without re-collecting everything each time.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `id` | `"7123456789012345678"` |
| `author.name` | `"Sample Creator"` |
| `author.profileUrl` | `"/@sample_creator123?region=us"` |
| `author.profileImageUrl` | `"https://p16-lemon8.byteimg.com/sample-avatar.jpeg"` |
| `author.userId` | `"6800000000000000001"` |
| `title` | `"Sample post title"` |
| `content` | `"Short preview text pulled from the post card..."` |
| `postUrl` | `"https://www.lemon8-app.com/@sample_creator123/7123456789012345678?region=us"` |
| `imageUrl` | `"https://p16-lemon8.byteimg.com/sample-cover.jpeg"` |
| `images` | `[{ "src": "https://...", "alt": "" }]` |
| `isVideo` | `false` (also `true` for video posts) |
| `statistics.likesCount` | `"450"` |
| `statistics.savedCount` / `statistics.commentsCount` | `"0"` on the post summary; the real counts are under `details.statistics` below |
| `details.fullContent` | `"The full post body text appears here..."` |
| `details.hashtags` | `["#sampletag", "#lemon8"]` |
| `details.publishedAt` | `"2025-01-15T09:30:00Z"` |
| `details.editTime` | `"1/16"` (last edit, no year) |
| `details.statistics.savedCount` / `.likesCount` / `.commentsCount` / `.viewsCount` | `"8"` / `"31"` / `"2"` / `"1500"` |
| `details.relatedTopics` | `["Sample Topic"]` |
| `comments` / `allComments` | first 5, and the full list, each with `author`, `content`, `commentId` |
| `commentStats.totalComments` / `.totalReplies` | `12` / `4` |
| `changeType` | `"NEW"` (also `"UPDATED"`, `"UNCHANGED"`, `"REAPPEARED"`, `"EXPIRED"`; incremental mode only) |

Profile-level fields, the account name, bio, follower and following counts, verification badge, social links and the optional following list, are written once per run to the run's key-value store (`OUTPUT` and `METADATA` records) rather than as separate dataset rows.

**Flat alias fields.** Each post row also carries flat copies of common fields, so spreadsheets and other Lemon8 scrapers' schemas line up: `groupId`, `url`, `articleClass`, `likes`, `saves`, `commentCount`, `authorUserId`, `authorUsername`, `authorNickname`, `authorAvatar`, `authorFollowers`, `videoUrl`, `thumbnailUrl`, `hashtags`, `topComments`, `keyword` (the profile handle), `category` (always null for profile posts), `region`, `sourceMode` (`profile` or `post`) and `scrapedAt`. `saves`, `commentCount`, `videoUrl`, `hashtags` and `topComments` need **Get details**. They never change the Incremental-mode verdict, so turning them on does not re-bill tracked posts. The United Kingdom storefront is not offered because Lemon8 serves the US storefront for it.

### How to Use

1. Pick how to target a profile: **Username** for one profile, **Profile URL** for one profile by link, or **Start URLs** for several profiles at once. Start URLs wins over Profile URL, which wins over Username.
2. Set **Post Limit** and **Region**, then turn on **Get Detailed Post Data** for full content, hashtags and comments (its own **Details Post Limit** caps how many posts get this treatment).
3. Optionally turn on **Scrape Following Profiles**, and **Save Images** / **Save Videos** to store post media in the run's storage.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read the profile bio and following list from the run's key-value store.

**Single profile by username:**

```json
{
  "username": "sample_creator123",
  "region": "us"
}
```

**Single profile by link, with full detail and media:**

```json
{
  "profileUrl": "https://www.lemon8-app.com/@sample_creator123?region=us",
  "limit": 50,
  "getDetails": true,
  "detailsLimit": 20,
  "saveImages": true
}
```

**Several profiles at once, plus following:**

```json
{
  "startUrls": [
    "https://www.lemon8-app.com/@sample_creator123?region=us",
    "https://www.lemon8-app.com/@sample_traveler88?region=au"
  ],
  "getFollowing": true,
  "followingLimit": 10
}
```

**Scheduled incremental monitoring:**

```json
{
  "username": "sample_creator123",
  "region": "us",
  "incrementalMode": true,
  "emitUnchanged": false
}
```

#### URL mode: supported link shapes

Start URLs accepts these shapes. **If you leave Start URLs untouched it is pre-filled with one example of each shape below, so a run with no changes scrapes all of them** (before this change an untouched Start URLs scraped nothing and used Username instead). If you set a different Username or a Profile URL while Start URLs is still the untouched example list, your Username or Profile URL is used instead. Duplicate targets (for example a profile with and without `?region=us`) are scraped once. Posts are also de-duplicated across targets for the whole run: a post that several targets reach (the same profile in two regions, a profile and its following-list link, a profile and one of its posts) is saved and billed once, from the first target in your list that returns it, and is not fetched for details again. In incremental mode this keeps the post's saved fields stable between runs, so the example list reports no changes on a repeat run with unchanged data.

| Shape | Example | What you get |
|---|---|---|
| Profile, region query | `https://www.lemon8-app.com/@sydneydelreyy?region=us` | Profile info and posts |
| Profile, no region | `https://www.lemon8-app.com/@sydneydelreyy` | Same, region from the Region input |
| Profile, other region | `https://www.lemon8-app.com/@sydneydelreyy?region=ca` | Same, in that region |
| Post | `https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794?region=us` | That one post with full details and comments |
| Post, no region | `https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794` | Same |
| Following list | `https://www.lemon8-app.com/@sydneydelreyy/follow?region=us` | The profile's posts plus the accounts it follows (Following Profiles Limit applies) |

Other regions, the `m.lemon8-app.com` host and the bare `lemon8-app.com` host are tried but logged as unverified shapes and may return nothing. Links without an `/@user` part (such as `/tag/...`) are skipped with a warning in the run log.

#### Output views

The dataset has these views: Overview, Images, Videos, Authors, Comments, Detailed content, Engagement, Following profiles and, for Incremental mode runs, Changes (`changeType`, `changedFields`, `firstSeenAt`, `lastSeenAt`).

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/lemon8-profile-scraper").call(run_input={"username": "sample_creator123", "region": "us"})
for post in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(post["title"], post["statistics"]["likesCount"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/lemon8-profile-scraper').call({ username: 'sample_creator123', region: 'us' });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Get Detailed Post Data and cost

Post cards alone only carry a title, content preview, image and like count. Turning on **Get Detailed Post Data** fetches each post's own page for full content, hashtags, publish date, save and comment counts, and the comment thread, up to **Details Post Limit** posts. The actor spends up to 30 seconds expanding each post's comment thread, so posts with very large comment sections may come back with a partial thread. At most 1000 comments are collected per post.

#### Resume and recurring updates

Two different things, both off by default:

- **Resume** (`resumeFromRunId`) continues one interrupted run: paste its run or dataset id and this run skips posts already collected there, so you are not charged twice.
- **Incremental mode** (`incrementalMode`) is for scheduling this actor on the same profile(s) again and again. Each post is classified `NEW`, `UPDATED`, `UNCHANGED` (suppressed and not billed unless `emitUnchanged` is on), `REAPPEARED` or `EXPIRED` (only after a run that fully scanned every tracked profile, and only with `emitExpired`). What is compared: every returned post field (text, title, images, author, comments, saved/likes/comments counters, details). What is excluded: signed-URL tokens and CDN host numbers on image and video links, comment ordering, files re-saved by Save Images/Videos, and the view counter (`details.statistics.viewsCount`); `ignoreFieldsForChanges` adds your own exclusions without a one-time wave of UPDATED rows, because the stored baseline is re-compared with the current list. A Post Limit cap or a blocked profile never produces EXPIRED rows. `stateKey` names or shares the stored state; leaving it empty derives one from the profile set, region and Get Detailed Post Data setting. The two features cannot be combined on a profile set that already has incremental state; use a different State key to start a separate campaign instead.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape, the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human readable summary of each post, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

1. Authorize a connector once under **Apify > Settings > Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the `mcpConnectors` input field. If the picker is empty, you have not authorized a connector yet.
3. For Notion, also set `notionParentPageUrl` to the page where items should be created. `maxNotifyListings` caps how many posts are sent per run.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `username` | string | (required) | Lemon8 username to scrape, without the `@`. Ignored if `profileUrl` is set. |
| `startUrls` | array | one example per supported shape | Lemon8 profile, post or following-list links (see the table above), up to Post Limit posts per profile. Takes precedence over `profileUrl` and `username`. |
| `profileUrl` | string | (none) | Full profile link for a single profile. Takes precedence over `username`, ignored if `startUrls` is set. |
| `region` | string | `us` | Target Lemon8 region: `us`, `au`, `nz`, `jp`, `th`, `id`, `vn`, `my`, `sg`, or `ca`. |
| `limit` | integer | `5` | Maximum posts to extract per profile, up to 5000. |
| `getDetails` | boolean | `true` | Fetch each post's own page for full content, hashtags, publish date and comments. |
| `detailsLimit` | integer | `5` | Maximum posts per profile to fetch full details for, up to 3000. |
| `commentExpansionTimeout` | integer | `30` | Currently not applied: the actor always uses a 30 second budget per post, whatever value is set here. |
| `resumeFromRunId` | string | (none) | Continue one interrupted run without re-returning or re-billing posts already collected there. |
| `incrementalMode` | boolean | `false` | Return only new, updated and reappeared posts on recurring scheduled runs. |
| `stateKey` | string | (none) | Name or share an incremental-mode state; derived automatically when left empty. |
| `emitUnchanged` | boolean | `false` | Incremental mode only: also return (and bill) posts unchanged since the last run. |
| `emitExpired` | boolean | `false` | Incremental mode only: also return (and bill) posts no longer found, once a run fully scans every tracked profile. |
| `ignoreFieldsForChanges` | array | `[]` | Incremental mode only: field names (bare name = any depth, or dotted path such as `details.statistics.likesCount`) that never count as a change and are left out of `changedFields`. They stay on every returned row. |
| `getFollowing` | boolean | `false` | Also scrape the profiles this account follows. |
| `followingLimit` | integer | `2` | Maximum following profiles to scrape. |
| `saveImages` | boolean | `false` | Download post images into the run's storage. |
| `saveVideos` | boolean | `false` | Download post videos into the run's storage. |
| `proxy` | object | prefilled Apify Proxy, US | Connection settings; falls back automatically if the first connection is refused. |
| `dev_transform_fields` | array | `[]` | Keep only these dot-notation fields (e.g. `statistics.likesCount`) in the pushed output. |
| `dev_dataset_name` | string | `default` | Save results into a custom named dataset; supports `{ACTOR}`, `{DATE}`, `{TIME}` placeholders. |
| `dev_dataset_clear` | boolean | `false` | Clear the target dataset before this run's results are inserted. |
| `mcpConnectors` | array | (none) | Optional: send a summary of each post to apps authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on posts written to each connector per run. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

```json
{
  "id": "7123456789012345678",
  "author": {
    "name": "Sample Creator",
    "profileUrl": "/@sample_creator123?region=us",
    "profileImageUrl": "https://p16-lemon8.byteimg.com/sample-avatar.jpeg",
    "userId": "6800000000000000001"
  },
  "title": "Sample post title",
  "content": "Short preview text pulled from the post card...",
  "postUrl": "https://www.lemon8-app.com/@sample_creator123/7123456789012345678?region=us",
  "imageUrl": "https://p16-lemon8.byteimg.com/sample-cover.jpeg",
  "statistics": {
    "savedCount": "0",
    "likesCount": "450",
    "commentsCount": "0"
  },
  "images": [
    { "src": "https://p16-lemon8.byteimg.com/sample-cover.jpeg", "alt": "" }
  ],
  "isVideo": false,
  "details": {
    "title": "Sample post title",
    "fullContent": "The full post body text appears here, hashtags stripped of markup...",
    "hashtags": ["#sampletag", "#lemon8"],
    "editTime": "1/16",
    "publishedAt": "2025-01-15T09:30:00Z",
    "statistics": {
      "savedCount": "8",
      "likesCount": "31",
      "commentsCount": "2",
      "viewsCount": "1500"
    },
    "galleryImages": [
      { "src": "https://p16-lemon8.byteimg.com/sample-gallery-1.jpeg", "alt": "" }
    ],
    "relatedTopics": ["Sample Topic"],
    "isVideo": false,
    "videoData": null
  },
  "comments": [
    { "author": "Sample Commenter", "authorTag": null, "content": "Sample comment text", "time": "1/16", "likes": "3", "replies": null, "commentId": "7123456789012345679" }
  ],
  "allComments": [
    { "author": "Sample Commenter", "authorTag": null, "content": "Sample comment text", "time": "1/16", "likes": "3", "replies": null, "commentId": "7123456789012345679" }
  ],
  "commentStats": {
    "totalComments": 12,
    "totalReplies": 4
  }
}
```

In incremental mode only, every row also carries `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt`. These fields never appear on a normal, non-incremental run.

### Plan Requirement

Lemon8 limits how many pages a single connection can read before it answers with an empty block page, so the actor is built to move between connections on its own. Datacenter and residential Apify Proxy access have not been measured against this site, so this page does not promise that any one proxy group works without action. The default proxy setting is the starting point, and the actor automatically moves to a backup connection when one is refused or the site answers with an empty block page.

What you will see in the run log:

- If the selected connection is unavailable (for example Apify free plans, which do not include residential proxies), the log says "The selected connection is unavailable to this run" and "Continuing on a backup connection; some pages may still be unavailable", and points to https://apify.com/pricing or your own proxy URLs.
- When the backup serves the pages, the log says "Served over the backup connection (the default connection was unavailable)."
- If the proxy connection is refused for the account, the run stops with "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required", and nothing is charged.
- If no connection can load the pages, the run stops with "No results: residential proxies are unavailable on this run ... and the backup connection could not load the requested Lemon8 pages", or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search."

For large or frequent pulls across many profiles, use a paid plan or your own proxy URLs, and check the actor's Pricing tab for current rates before running at scale.

### FAQ

#### How much does it cost?

You pay per post returned. The **Pricing** tab on the actor page shows the current rates. Use **Post Limit** to cap the cost of any run.

#### Is it legal to scrape Lemon8?

This actor collects only publicly available profile and post data. You are responsible for how you use it: follow Lemon8's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution of the results.

#### What is the difference between Resume and Incremental mode?

Resume continues one specific interrupted run from a pasted run or dataset id. Incremental mode is for scheduling this actor on the same profile(s) again and again and getting only what changed. They solve different problems and cannot be combined on a profile set that already has saved incremental state; use a separate State key to start a new campaign if you need both.

#### Why did my run fail instead of returning an empty dataset?

If every request to a profile page is refused, the run stops with a clear message and nothing is charged, so a blocked run is never confused with a profile that genuinely has no posts. Try again later, pick a different proxy country, or supply your own proxy URLs. On Apify free plans, which do not include residential proxies, a backup connection is used automatically. A profile that truly has zero posts, or that does not exist, succeeds quietly with an empty dataset instead.

#### Can I get only new posts on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then returns only new, updated and reappeared posts, and unchanged ones are not billed unless you turn that on too.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the `mcpConnectors` field to push a summary of each post into Notion, Linear or Airtable.

### 🔗 Want more Lemon8 data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>📱 <a href="https://apify.com/abotapi/lemon8-discover-scraper"><b>Lemon8 Search Scraper</b></a><br>Scrape Lemon8 posts by keyword across multiple regions. Extract posts, images, videos...</td><td>📱 <a href="https://apify.com/abotapi/lemon8-feeds-scraper"><b>Lemon8 Feed Scraper</b></a><br>Scrape Lemon8 feeds across 22 categories and 10+ regions. Extract posts, images, videos...</td></tr>
<tr><td>📱 <a href="https://apify.com/abotapi/lemon8-media-scraper"><b>Lemon8 Media Scraper</b></a><br>Lightweight Lemon8 scraper for extracting image and video URLs from posts, with optional...</td><td>📱 <a href="https://apify.com/abotapi/truthsocial-com-scraper"><b>Truth Social Scraper</b></a><br>Scrape public Truth Social profiles, posts, media, metrics, author data, and complete...</td></tr>
<tr><td>📱 <a href="https://apify.com/abotapi/reddit-scraper"><b>Reddit⚡ Lightning</b></a><br>From $1/1K. Scrape Reddit posts, comments, and media from any subreddit or user profile -...</td><td>🧩 <a href="https://apify.com/abotapi/pikabu-scraper"><b>Pikabu Scraper</b></a><br>Scrape Pikabu (Пикабу): keyword search, hot/new/best feeds, communities, tags, full story...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/lemon8-profile-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `username` (type: `string`):

Lemon8 username to scrape, without the '@'. Ignored if a Profile URL is provided below.

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

Lemon8 URLs to scrape. Supported: a profile (/@user, with or without ?region=), a single post (/@user/<postId>) and a following list (/@user/follow). Left untouched, this scrapes one example of each shape. Unverified shapes (other regions, m. or bare host) are tried with a warning; /tag/ and feed links are skipped with a warning. Takes precedence over Username and Profile URL, unless it is still the untouched example list and you set a different Username or a Profile URL.

## `profileUrl` (type: `string`):

Full profile URL for a SINGLE profile, e.g. https://www.lemon8-app.com/@username?region=us. Takes precedence over Username. Ignored if Start URLs is provided.

## `region` (type: `string`):

Target region for Lemon8 content

## `limit` (type: `integer`):

Maximum number of posts to extract per profile (max 500)

## `getDetails` (type: `boolean`):

Navigate to individual post pages to extract full content and all comments

## `detailsLimit` (type: `integer`):

Maximum number of posts to get detailed data for

## `commentExpansionTimeout` (type: `integer`):

Maximum time in seconds to spend expanding comments on each post. Posts with many comments may timeout.

## `getFollowing` (type: `boolean`):

Automatically scrape profiles that the main user is following

## `followingLimit` (type: `integer`):

Maximum number of following profiles to scrape

## `saveImages` (type: `boolean`):

Download post images locally

## `saveVideos` (type: `boolean`):

Download videos from video posts

## `proxy` (type: `object`):

Proxy for requests. Defaults to Apify datacenter (US); if the datacenter tunnel is unavailable or gets blocked, the actor automatically falls back to a backup proxy pool.

## `dev_transform_fields` (type: `array`):

Transform the resulting output. Select only needed fields. For nested object use DOT (e.g., 'statistics.rating'). For nested array use NUMBER as array index (e.g., 'comments.0.text').

## `dev_dataset_name` (type: `string`):

Save results into custom named Dataset. Use masks to customize: {ACTOR} = actor name, {DATE} = date (YYYYMMDD), {TIME} = time (HHMMSS). Example: 'lemon8-{DATE}' will create 'lemon8-20250519'.

## `dev_dataset_clear` (type: `boolean`):

Clear Dataset before inserting new data

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large pull of posts without returning or charging for posts already collected there. Use this after an interrupted run, or when continuing a pull for the same profile(s) in another run. For recurring daily monitoring of the same profile(s), use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching posts as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED posts. Turn on "Emit unchanged" or "Emit expired" only when you also want those posts returned (and billed). State is kept separately for each username/Profile URL/Start URLs set, region, and Get Detailed Post Data setting; use State key when you want to name or deliberately share a monitoring campaign. UPDATED means the post's own content changed. Compared: every returned post field (text, title, images, author, comment lists, saved/likes/comments counters, details). Excluded: signed-URL tokens and CDN host numbers on image/video links, comment order, files re-saved by Save Images/Videos, and the view counter (details.statistics.viewsCount); add your own with "Ignore fields when detecting changes". Details: the post's view counter (details.statistics.viewsCount) is a live engagement number that keeps ticking on its own, so a post whose view count alone moved stays UNCHANGED and is not returned or billed again. The current view count is still on every returned row. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

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 the username/Profile URL/Start URLs, region, and Get Detailed Post Data setting — different profile setups then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return posts 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.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return posts that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned every tracked profile — not when Post Limit capped it, or when Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## `ignoreFieldsForChanges` (type: `array`):

Incremental mode only. Field names that must NOT count as a change when deciding NEW vs UPDATED vs UNCHANGED, and are left out of changedFields. A bare name (e.g. savedCount) is ignored at any depth; a dotted path (e.g. details.statistics.likesCount) ignores just that field. The ignored fields still appear, with their current values, on every returned row. Applied to the stored baseline too, so changing this list never triggers a one-time wave of UPDATED rows. Leave empty to use the built-in rules (see Incremental changes above).

## `mcpConnectors` (type: `array`):

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` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "username": "sydneydelreyy",
  "startUrls": [
    "https://www.lemon8-app.com/@sydneydelreyy?region=us",
    "https://www.lemon8-app.com/@sydneydelreyy",
    "https://www.lemon8-app.com/@sydneydelreyy?region=ca",
    "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794?region=us",
    "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794",
    "https://www.lemon8-app.com/@sydneydelreyy/follow?region=us"
  ],
  "region": "us",
  "limit": 5,
  "getDetails": true,
  "detailsLimit": 5,
  "commentExpansionTimeout": 30,
  "getFollowing": false,
  "followingLimit": 2,
  "saveImages": false,
  "saveVideos": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  },
  "dev_transform_fields": [],
  "dev_dataset_name": "default",
  "dev_dataset_clear": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

Main post records with author, URL, content preview, and engagement counts.

## `images` (type: `string`):

Image-focused view for scraped Lemon8 posts.

## `videos` (type: `string`):

Video post records and video metadata where available.

## `authors` (type: `string`):

Author profile fields collected from post records.

## `comments` (type: `string`):

Comments and expanded comment data when detail scraping is enabled.

## `detailedContent` (type: `string`):

Full post content, hashtags, related topics, and detail fields.

## `engagement` (type: `string`):

Saved, likes, comments, and detailed engagement fields.

## `followingProfiles` (type: `string`):

Profiles followed by the scraped account when following-profile scraping is enabled.

## `changes` (type: `string`):

New, updated and expired posts with changeType, changedFields, firstSeenAt and lastSeenAt (incremental mode).

## `completeOutput` (type: `string`):

Profile-level output stored in the default key-value store.

## `metadata` (type: `string`):

Run metadata with profile count, post count, and scraping summary fields.

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "username": "sydneydelreyy",
    "startUrls": [
        "https://www.lemon8-app.com/@sydneydelreyy?region=us",
        "https://www.lemon8-app.com/@sydneydelreyy",
        "https://www.lemon8-app.com/@sydneydelreyy?region=ca",
        "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794?region=us",
        "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794",
        "https://www.lemon8-app.com/@sydneydelreyy/follow?region=us"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyCountry": "US"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/lemon8-profile-scraper").call(input);

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {
    "username": "sydneydelreyy",
    "startUrls": [
        "https://www.lemon8-app.com/@sydneydelreyy?region=us",
        "https://www.lemon8-app.com/@sydneydelreyy",
        "https://www.lemon8-app.com/@sydneydelreyy?region=ca",
        "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794?region=us",
        "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794",
        "https://www.lemon8-app.com/@sydneydelreyy/follow?region=us",
    ],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyCountry": "US",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/lemon8-profile-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "username": "sydneydelreyy",
  "startUrls": [
    "https://www.lemon8-app.com/@sydneydelreyy?region=us",
    "https://www.lemon8-app.com/@sydneydelreyy",
    "https://www.lemon8-app.com/@sydneydelreyy?region=ca",
    "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794?region=us",
    "https://www.lemon8-app.com/@sydneydelreyy/7499465815561994794",
    "https://www.lemon8-app.com/@sydneydelreyy/follow?region=us"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/lemon8-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/lemon8-profile-scraper"
        }
    }
}
```

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

## OpenAPI specification

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