# Lemon8 Feed Scraper: Posts, Comments, Analytics & Media (`abotapi/lemon8-feeds-scraper`) Actor

Scrape Lemon8 feeds across 22 categories and 10+ regions. Extract posts, images, videos, comments, engagement metrics, and post analytics with support for infinite scrolling and high-quality media downloads. Ideal for content monitoring, research, and trend analysis.

- **URL**: https://apify.com/abotapi/lemon8-feeds-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Social media, Developer tools, Automation
- **Stats:** 16 total users, 0 monthly users, 87.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Lemon8 Feeds Scraper

![Lemon8 Scraper Banner](https://i.postimg.cc/CLMPG9ZY/banner.png)

This actor extracts posts, images, videos, comments, and analytics from Lemon8 feeds across 22 categories and 10+ regions. Supports infinite scrolling, full media downloads, post-level analytics, and detailed comment extraction—perfect for research, analysis, or content monitoring.

### Features

- **22 Feed Categories** - Scrape from For You, Beauty, Food, Fashion, and more
- **10+ Regions** - Support for US, Australia, Japan, and more
- **Full Post Data** - Titles, content, statistics, hashtags
- **Comment Extraction** - All comments including replies
- **Media Downloads** - Save images and videos to Key-Value Store
- **Reliable Access** - Smart proxy rotation with automatic fallback

### Input Configuration

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `category` | int | required | Feed category (0-21) |
| `region` | string | "us" | Region code |
| `limit` | int | 100 | Max posts to extract |
| `getDetails` | bool | true | Extract full post details |
| `detailsLimit` | int | 10 | Max posts for detail extraction |
| `saveImages` | bool | false | Download images to KVS |
| `saveVideos` | bool | false | Download videos to KVS |
| `proxy` | object | null | Proxy configuration |
| `resumeFromRunId` | string | "" | Continue one interrupted run/dataset without re-collecting or re-charging its posts |
| `incrementalMode` | bool | false | Turn on for recurring monitoring — classifies each post as NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED against the previous run |
| `stateKey` | string | "" | Name a monitoring campaign explicitly; otherwise the state key is derived from category/startUrls + region + getDetails |
| `emitUnchanged` | bool | false | Also return (and bill) UNCHANGED posts every run |
| `emitExpired` | bool | false | Also return (and bill) posts no longer found, once a run fully scans every feed |

#### Example Input

```json
{
  "category": 2,
  "region": "us",
  "limit": 50,
  "getDetails": true,
  "detailsLimit": 10,
  "saveImages": false,
  "saveVideos": false
}
```

#### 🔁 Resume & recurring updates

Two different features, both opt-in:

- **Resume** (`resumeFromRunId`) continues ONE specific interrupted run: paste a previous run ID or dataset ID and this run skips posts it already collected.
- **Incremental mode** (`incrementalMode`) is for scheduling this actor on a recurring basis against the same feed. The actor remembers what it saw last time (keyed by `stateKey`, or an automatic key derived from category/startUrls + region + getDetails) and adds four fields to every dataset row:

```json
{
  "changeType": "NEW",
  "changedFields": [],
  "firstSeenAt": "2026-07-30T03:00:00Z",
  "lastSeenAt": "2026-07-30T03:00:00Z"
}
```

`changeType` is one of `NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, `EXPIRED`. `UNCHANGED` and `EXPIRED` posts are suppressed (not returned or billed) unless you turn on `emitUnchanged` / `emitExpired`. `EXPIRED` posts are only produced once a run has scanned every tracked category/Start URL to its natural end — a Post Limit cap, a block, or `resumeFromRunId` all skip EXPIRED detection for that run rather than risk a false tombstone. These fields never appear when `incrementalMode` is off.

### Categories

| ID | Name | ID | Name |
|----|------|----|------|
| 0 | For You | 11 | Travel |
| 1 | Beauty | 12 | Money |
| 2 | Food | 13 | Career |
| 3 | Fashion | 14 | Art |
| 4 | Home | 15 | Pets |
| 5 | Wellness | 16 | Photography |
| 6 | Fitness | 17 | Gaming |
| 7 | Entertainment | 18 | Reading |
| 8 | Relationship | 19 | Cars |
| 9 | Tech | 20 | Outdoors |
| 10 | Parenting | 21 | Education |

### Regions

`us`, `au`, `nz`, `jp`, `th`, `id`, `vn`, `my`, `sg`, `ca`

### 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 record — 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 **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

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

### Output Format

Each dataset record has the following structure:

```json
{
  "posts": [
    {
      "id": "7412987407534162437",
      "author": {
        "name": "Author Name",
        "profileUrl": "https://.../",
        "profileImageUrl": "https://.../"
      },
      "title": "Post Title",
      "content": "Content preview...",
      "postUrl": "https://.../",
      "statistics": {
        "savedCount": "0",
        "likesCount": "6437",
        "commentsCount": "0"
      },
      "images": [...],
      "isVideo": false,
      "category": "Food",
      "categoryId": 2,
      "details": {...},
      "allComments": [...],
      "commentStats": {...}
    }
  ],
  "metadata": {
    "feedsUrl": "https://.../",
    "category": "Food",
    "categoryId": 2,
    "region": "us",
    "totalScraped": 50,
    "scrollsPerformed": 15,
    "videoPostsFound": 5,
    "detailedPostsScraped": 10
  }
}
```

# Actor input Schema

## `category` (type: `integer`):

Feed category: 0=ForYou, 1=Outfits, 2=Skincare, 3=Nails, 4=Home, 5=Recipes, 6=Makeup, 7=Hair, 8=Fitness, 9=Accessories, 10=Perfume, 11=MentalHealth, 12=Relationship, 13=Wellness, 14=Baking, 15=Music, 16=Shoes, 17=Travel, 18=Tattoo, 19=Drinks, 20=Dining, 21=HomeSkills, 22=Bags, 23=Reading, 24=Photography, 25=Movie, 26=Outdoors, 27=Tech, 28=Art\&Design, 29=Gardening, 30=Career, 31=Games, 32=Education, 33=Cars, 34=Wedding, 35=Maternity, 36=Pets

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

Lemon8 feed URLs to scrape, e.g. https://www.lemon8-app.com/feed/outfits?region=us . When provided, these take precedence over Category: each URL's category and region are parsed and scraped (up to Post Limit posts per URL). Leave empty to scrape by Category instead.

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

Region: us=United States, au=Australia, nz=New Zealand, jp=Japan, th=Thailand, id=Indonesia, vn=Vietnam, my=Malaysia, sg=Singapore, ca=Canada

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

Maximum number of posts to extract (max 5000)

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

## `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 feed pull in another run. For recurring daily monitoring of the same feed, 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 category/Start URL, region, and Get Detailed Post Data setting; 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.

## `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 category/Start URLs, region, and Get Detailed Post Data setting — different feed 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 category/Start URL — 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.

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

Download post images locally and store in key-value store

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

Download videos from video posts and store in key-value store

## `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 output to include only specified fields. Use dot notation for nested objects.

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

Save results into a custom named Dataset. Placeholders: {ACTOR}, {DATE}, {TIME}

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

Clear the dataset before inserting new data

## `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
{
  "category": 0,
  "startUrls": [],
  "region": "us",
  "limit": 2,
  "getDetails": true,
  "detailsLimit": 2,
  "commentExpansionTimeout": 30,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "saveImages": false,
  "saveVideos": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  },
  "dev_transform_fields": [],
  "dev_dataset_name": "default",
  "dev_dataset_clear": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

Main feed post records with author, URL, category, media type, and engagement counts.

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

Image-focused view for scraped Lemon8 feed posts.

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

Video feed posts and video metadata where available.

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

Author profile fields collected from feed 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`):

Likes, comments, and detailed engagement fields.

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

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

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

Run metadata with feed/category counts 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 = {
    "category": 0,
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/lemon8-feeds-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 = {
    "category": 0,
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/lemon8-feeds-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 '{
  "category": 0,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  }
}' |
apify call abotapi/lemon8-feeds-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/lemon8-feeds-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/cnP7XkYWf0RktZZeX/builds/4gLcsZUoW2jSaqxN4/openapi.json
