A clock, collection card, success gate, and storage stack form a connected workflow.
A reliable workflow checks the run before it stores the rows.

This guide provides a reference method for you to build and test locally, establishing a repeatable ingestion workflow rather than a pre-built import or a verified complete deployment. A checkpoint is a saved record of your execution progress, and an upsert is a database operation that inserts a new row or updates an existing record if a duplicate unique key match occurs.

Technical Scope and Operational Limits

Before configuring your n8n workflow, you must understand what this extraction pipeline handles and where its boundaries lie. This system focuses strictly on automated data extraction and persistent storage. It does not perform spam filtering, sentiment analysis, customer intent scoring, automated replies, or content moderation. If you need to group comments into custom categories, read our guide on Facebook Comments Customer Feedback Analysis. If you need to route support questions into an active desk, check out our tutorial on the Facebook Unanswered Comment Questions Queue.

This tutorial covers technical implementation using standard n8n nodes and the HTTP API for the Facebook Comments Scraper. An API (Application Programming Interface) is a set of rules and endpoints that lets different software programs talk to each other over the web. The scraper accepts specific, known public post URLs as inputs. It does not accept general profile links, group URLs, or brand channel pages. When executed, the scraper returns flat data records formatted as JSON (JavaScript Object Notation), which is a standard text format for sharing structured data.

Each output row represents either a top-level comment or a direct nested reply. The returned payload includes string identifiers like commentId and contentId. Note that authorId and publishedAt may be null, publishedAt and scrapedAt are timestamps, and isReply is a boolean value rather than an exact string identifier. The raw JSON object preserves parentCommentId, rootCommentId, isReply, text, and null values. Across runs, your database handles deduplication using a composite unique constraint on contentId and commentId implemented via parameterized queries.

Keep the following operational parameters in mind as you configure your pipeline:

  • Target Links: You must pass between 1 and 100 explicit public post URLs as string items inside an array.
  • Result Caps: The parameter maxResultsPerPost sets the maximum number of comment and reply rows collected per post. Setting this to 25 limits the run to at most 25 rows per post.
  • Reply Extraction: Setting includeReplies to true tells the scraper to collect nested replies alongside parent comments.
  • Full Extraction: Setting collectAllAvailable to true bypasses the numeric result cap, though it remains subject to platform visibility limits and compute charges.
  • Sorting Parameters: Sort options like all, newest, or most_relevant determine how Facebook orders comments before extraction, operating independently of result caps.

Core API Endpoints Reference

The following table summarizes the endpoints used in this workflow, along with their raw URL structures and expected response fields:

Core API Endpoints Reference
Endpoint URLDescriptionExpected Response Fields
https://api.apify.com/v2/acts/chronometrica~facebook-comments-scraper/runsLaunches the scraper rundata.id, data.defaultDatasetId, data.defaultKeyValueStoreId, data.status
https://api.apify.com/v2/actor-runs/RUN_IDChecks execution statusdata.status
https://api.apify.com/v2/datasets/DATASET_ID/items?format=json&clean=false&offset=0&limit=100Fetches dataset item pagesJSON array of comment records
https://api.apify.com/v2/key-value-stores/STORE_ID/records/OUTPUTInspects run summary storeRun-specific summary record

Note: Replace placeholders like RUN_ID, DATASET_ID, and STORE_ID with your actual saved execution values. Never include access tokens directly inside URL strings.

Step-by-Step Architecture and Node Sequence

To build this pipeline in n8n, you will configure a structured sequence of built-in nodes. You will need n8n installed, an Apify API token stored in an n8n Header Auth credential (named Authorization with value Bearer your_token), and a relational database credential (such as Postgres).

1. Triggers and Credentials Setup

Start by creating a new workflow in n8n. Open your workflow settings, select your local time zone, and leave the workflow unpublished while you build and test your components.

You will create two entry points:

  • Schedule Trigger: Triggers your recurring daily or hourly collection run automatically based on your time zone settings.
  • Manual Trigger and Recovery Input: A separate manual entry point for operators. Because a manual trigger cannot accept a run ID directly, place an Edit Fields node after it where an operator can input an existing saved run ID. This lets you recover stalled runs without launching a new scraping job.

2. Launching the Scraper

Connect your schedule trigger to an HTTP Request node named Launch Scraper. Set the method to POST and target the Apify actor run endpoint. Attach your Header Auth credential. Configure a small plain JSON request body using raw URL strings:

text
{
  "startUrls": [
    "https://www.facebook.com/story.php?story_fbid=123456789&id=987654321"
  ],
  "maxResultsPerPost": 25,
  "includeReplies": true,
  "collectAllAvailable": false,
  "commentSortMode": "all"
}
Step-by-Step Architecture and Node Sequence

When this request succeeds, the Apify API returns an envelope containing execution metadata. Your workflow must capture and save four values immediately: data.id, data.defaultDatasetId, data.defaultKeyValueStoreId, and data.status.

Save these values into a durable database checkpoint keyed by the run ID, initializing the attempt count at zero and the next offset at zero. Durable means stored permanently in a relational database outside temporary workflow memory.

Critical Safety Rule: Never auto-retry an ambiguous launch POST request if a network timeout occurs. If the first request reached the server, a blind retry will launch a second billable scraping run. If a launch is ambiguous, inspect your Apify account run list manually before triggering a new one.

3. The Recovery Path

If an execution fails or stalls, the manual recovery branch selects the existing checkpoint record using the operator-provided run ID, skipping the launch node entirely.

Your workflow enforces a rule of one active execution per run ID. If a recovered run already shows a terminal saved status of SUCCEEDED in the database, the workflow skips status polling completely and jumps straight to page loading. If the saved status is failed, it routes to manual review. Other states enter bounded polling. Attempt counts are never automatically reset by recovery runs.

4. Status Polling and Counter Gate

Before each status check, your workflow queries the database to check the current attempt count. If the attempt count has reached 30, the system routes execution to a manual review branch to prevent infinite loops.

If the count is below 30, the workflow increments the attempt count in the database, pauses execution for 10 seconds using a Wait node, and then uses an HTTP GET request to check the run status from the Apify API (https://api.apify.com/v2/actor-runs/RUN_ID).

Network request errors during polling should use bounded read retries (maximum 3 attempts with a 10-second wait), rather than retrying POST requests.

The workflow evaluates the returned status:

  • SUCCEEDED: The workflow saves the flat status to the database and proceeds to dataset fetching.
  • READY / RUNNING / ABORTING / TIMING-OUT: The workflow routes execution back to the counter gate to wait and check again.
  • FAILED / ABORTED / TIMED-OUT: The workflow records the failure status and stops or routes to manual review.
  • Unknown Status: Routes to manual review.

Note: Stopping your polling loop does not cancel the remote Apify actor; it simply stops your n8n workflow from waiting. A poll timeout does not mean the post had zero comments.

5. Pagination and Page Loading

Once the run succeeds, your workflow enters the pagination loop. Before fetching each page, it reloads the current checkpoint state from the database to grab the latest offset and dataset ID.

It makes an HTTP GET request to fetch dataset items (https://api.apify.com/v2/datasets/DATASET_ID/items?format=json&clean=false&offset=0&limit=100, substituting the current offset and saved dataset ID). You must target the specific run dataset ID rather than a generic latest alias. Set the request format to JSON, use clean=false, and set limit=100.

Configure the HTTP node to return the full response body. Record the length of the incoming array before passing data to any splitting nodes. If the initial page array is completely empty, bypass splitting and inspect the key-value store output record via its dedicated endpoint (https://api.apify.com/v2/key-value-stores/STORE_ID/records/OUTPUT) using the saved store ID to determine if an error occurred. For subsequent pages, an empty array simply signals the end of collection.

6. Splitting and Database Upsert

Pass the dataset array into a Split Out node configured with an explicit destination field named comment.

Your downstream database storage node receives each split item and maps fields directly from comment. It validates that non-empty string identifiers and valid timestamps exist. It executes an upsert operation using parameterized queries against a composite unique key constraint (contentId and commentId). An upsert inserts a new row or updates an existing record if a duplicate match occurs.

To prevent old data from overwriting fresh updates, configure your database update condition so that incoming text and metadata update only if the incoming scrapedAt timestamp is greater than or equal to the stored timestamp. This represents the latest observed state of the public post, rather than an immutable historical audit log or deletion proof.

7. Advancing the Checkpoint

After every item in the current page writes successfully to the database, your workflow updates the checkpoint offset in the database by adding 100.

Crucial Rule: Never advance your checkpoint offset once per comment. You must update the checkpoint offset exactly once per page after the entire batch succeeds. If a database write fails midway through a page, the checkpoint offset remains unchanged, allowing your workflow to safely replay the page without duplicating records.

Preserve the current page length metadata separately across the split and database steps. The final check uses the current page length, not the first loop's length. If the current page length was less than 100 items, collection is complete and the workflow finishes. If the page length equals 100, the workflow loops back to reload the checkpoint and fetch the next batch.

Reader Testing and Validation Protocol

Before publishing your workflow to run automatically in production, you must build and test your workflow locally using structured verification checks. Do not rely on untested templates.

  1. Isolated Ingestion Test: Inject a frozen test fixture input {body: [25 comments]} directly into a Split Out node routed to your database node and configured to STOP immediately, bypassing all live checkpoint and page-summary nodes. Verify that your database stores exactly 25 rows. Running the exact same fixture a second time results in 0 new rows inserted and existing records evaluated without regression. Adding a distinct 26th record inserts exactly 1 new row. Furthermore, verify that an older fixture cannot overwrite newer text.
  2. Pagination Fixture Test: Test your offset loop using a stubbed checkpoint and 201 records across 3 pages of 100, 100, and 1 without incurring any paid Actor calls.
  3. Fault Tolerance and Polling Test: Test that max poll counts trigger manual review properly on the polling path. Simulate a database write failure on an intermediate page. Verify that your checkpoint offset remains unchanged, that recovery does not re-launch the scraper, and that non-succeeded statuses correctly block dataset fetching.
  4. Live Manual Verification: Run a single manual test against a real public post link. Review your platform limits, compute costs, and execution logs.

Only after all local tests pass and your schedule time zone is correctly configured should you save and publish your n8n workflow.

Sources & further reading

By Chronometrica · Updated

Back to top ↑