WordPress Posts & Pages Scraper avatar

WordPress Posts & Pages Scraper

Pricing

from $1.90 / 1,000 saved post or pages

Go to Apify Store
WordPress Posts & Pages Scraper

WordPress Posts & Pages Scraper

Export public WordPress posts and pages with HTML, plain text, dates, categories and tags. Bounded REST API requests and clear run summaries, with no WordPress login.

Pricing

from $1.90 / 1,000 saved post or pages

Rating

0.0

(0)

Developer

Cliqto Media

Cliqto Media

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Share

Export public WordPress posts and pages with HTML, plain text, dates, categories and tags. Add one site URL for a small content sample. The site must allow its public WordPress REST API. Limits and source errors are shown in the run summary.

WordPress Posts & Pages Scraper: public content, structured fields and JSON/CSV export

The event price is $0.0045 per start plus $0.0019 per saved record. Apify platform usage is charged separately. Empty runs still have a start charge.

Table of contents

What it does

The Actor reads the public WordPress REST API. It collects published post and page records. It also reads category and tag details embedded in the API response. It saves one Dataset row per unique record.

It reads records in date order, newest first. It uses /wp-json/wp/v2/posts and /pages. If the first route returns 404, it tries the rest_route query format. It only sends GET requests. It does not change the source site.

Private posts, drafts, password-protected content, custom post types, author profiles, comments and media files are outside this product. If a site adds another type to its posts endpoint, that type is skipped and counted.

Data you get

Each record has its WordPress ID, link, type, title, publication dates and edit dates. HTML and plain text are separate fields. Posts include category and tag IDs. Names and links are included when the API returns them. Standard pages have no categories or tags, so these arrays are empty.

The Dataset contains only content records. The key-value store, or KVS, contains OUTPUT with the same rows and a summary, plus RUN_SUMMARY with site results and counters. An empty Dataset alone does not tell you whether a run worked. Check the summary.

Quick start

  1. Open Input.
  2. Add https://wordpress.org/news to WordPress site URLs (siteUrls).
  3. Choose posts and pages.
  4. Set maxResults to 4, perPage to 2 and maxPagesPerType to 1.
  5. Click Start. Open the Dataset and check id, titleText and link.
  6. Open KVS RUN_SUMMARY. The sample is partial because more posts exist.

This tested sample returns 2 posts and 2 pages. Source data can change after a test.

Input fields

KeyTypeRequiredRuntime default / UI prefillRangeWhat it changesExample and advice
siteUrlsarray of URL stringsYesNo runtime default. UI prefill: WordPress News1–5 URLs, each up to 2,048 charactersSites to read; duplicates removed["https://wordpress.org/news"]. Use the site root or WordPress subdirectory. A /wp-json or /wp-json/wp/v2 root is also accepted.
contentTypesarray of stringsNo["posts", "pages"]posts, pages; 1–2 valuesSelects content in the given order; duplicate types removed["pages"] for a page export.
maxResultsintegerNo1001–1,000Global saved row limit across all sites and types4 for a first test. Earlier sites and types use the limit first.
maxPagesPerTypeintegerNo51–20API page limit for each site and type1 for a small test; increase for a larger export.
perPageintegerNo201–100Source records requested in one API page20 is a safe start. Large pages may hit the response size limit.
searchstringNo""Up to 200 characters; no control charactersWordPress source-side search for all chosen types"WordPress". Empty means no search filter.
requestDelayMsintegerNo1000500–5,000 msDelay before each collection requestKeep 1000; increase it for a small site.

Empty input, empty arrays, null values and unknown keys are rejected. Only public HTTP or HTTPS URLs on ports 80 or 443 are accepted. Do not add a login, URL query or fragment. Links in output are not fetched.

maxResults is shared. For example, if posts fill the limit, later pages or sites are marked partial and are not read. perPage controls fetched rows; maxResults controls saved rows. A small result limit can still require a full API page. Search runs on WordPress. This Actor has no local filter that scans every item after a search with no matches.

Input examples

Small posts and pages sample

{"siteUrls":["https://wordpress.org/news"],"contentTypes":["posts","pages"],"maxResults":4,"perPage":2,"maxPagesPerType":1}

Expected: 4 content rows, partial, and a PAGE_LIMIT outcome for posts. The event charge is $0.0121 plus platform usage.

Search with no matches

{"siteUrls":["https://wordpress.org/news"],"contentTypes":["posts","pages"],"search":"zzzz-no-match-wordpress-2a50fbd9","maxResults":4,"perPage":2,"maxPagesPerType":1}

Tested result: 0 content rows, complete, 2 collection requests. The event charge is $0.0045 plus platform usage.

Bounded larger export

{"siteUrls":["https://wordpress.org/news"],"contentTypes":["posts"],"maxResults":1000,"perPage":100,"maxPagesPerType":20}

Stop at 1,000 saved posts or an earlier page, time, request or response size limit. The summary explains the stop. This is a bounded sample, not a promise to return every post on a site.

Output example

This is a trimmed record from the small WordPress News sample. The HTML and text values below show only their first 160 characters. The full run stores the complete source values within the size limits.

{
"sourceUrl": "https://wordpress.org/news",
"recordType": "POST",
"id": 21731,
"type": "post",
"status": "publish",
"link": "https://wordpress.org/news/2026/09/wordpress-7-1-2-release/",
"date": "2026-09-22T14:01:20",
"date_gmt": "2026-09-22T14:01:20",
"title": {
"rendered": "WordPress 7.1.2 Release"
},
"titleText": "WordPress 7.1.2 Release",
"categories": [
14,
15
],
"tags": [],
"categoryDetails": [
{
"id": 14,
"name": "Releases",
"slug": "releases",
"link": "https://wordpress.org/news/category/releases/"
},
{
"id": 15,
"name": "Security",
"slug": "security",
"link": "https://wordpress.org/news/category/security/"
}
],
"tagDetails": [],
"extractionStatus": "complete",
"content": {
"rendered": "\n<p class=\"wp-block-paragraph\">This security release features a fix for a critical severity security vulnerability.</p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong",
"protected": false
},
"contentText": "This security release features a fix for a critical severity security vulnerability.\n\nBecause this is a security release, it is recommended that you update your"
}

Output fields

All fields below are present in each Dataset row. null means a source value was not available or had the wrong type. Empty text is a valid source value. HTML stays as supplied by the source; plain text removes tags, scripts and styles and decodes HTML entities.

FieldTypeNull / emptyExampleMeaning
sourceUrlstringNever nullhttps://wordpress.org/newsNormalized site input.
recordTypestringNever nullPOST or PAGEDataset content class.
idintegerNever null21731WordPress ID, unique within a site and content type. Use sourceUrl + type + id as the key.
typestringNever nullpost or pageSource WordPress type.
statusstringNever nullpublishOnly published content is saved.
slugstring or nullMay be null or emptywordpress-7-1-2-releaseSource URL name.
linkstringNever null; source may be emptyhttps://wordpress.org/news/2026/09/wordpress-7-1-2-release/Source content link; not fetched.
datestring or nullMay be null2026-09-22T14:01:20Published date in the site's timezone. No timezone is added.
date_gmtstring or nullMay be null2026-09-22T14:01:20Published date in UTC, in WordPress format.
modifiedstring or nullMay be null2026-09-23T14:04:10Last edit date in the site's timezone.
modified_gmtstring or nullMay be null2026-09-23T14:04:10Last edit date in UTC, in WordPress format.
titleobjectNever null{"rendered":"..."}Contains title.rendered, a source HTML string that can be empty.
titleTextstringCan be emptyWordPress 7.1.2 ReleasePlain text title.
contentobjectNever null{"rendered":"<p>...</p>","protected":false}content.rendered is HTML; content.protected is always false for saved rows.
contentTextstringCan be emptyWordPressPlain text content.
excerptobjectNever null{"rendered":"<p>...</p>","protected":false}Source summary HTML in excerpt.rendered; excerpt.protected is false.
excerptTextstringCan be emptyA short summaryPlain text excerpt.
categoriesinteger array or nullEmpty for standard pages; null for invalid source taxonomy[14, 15]Category IDs.
tagsinteger array or nullEmpty for standard pages; null for invalid source taxonomy[]Tag IDs.
categoryDetailsobject array or nullEmpty for no categories; null for invalid taxonomy[{"id":2,"name":"News","slug":"news","link":"https://example.org/news"}]Each object has integer id and nullable string name, slug, link. Names/links come from embedded terms.
tagDetailsobject array or nullEmpty for no tags; null for invalid taxonomy[]Same object shape as categoryDetails, for post tags.
extractionStatusstringNever nullcomplete or partialRow status. Missing term names make a row partial. It is separate from the run status.
observedAtstringNever null2026-10-04T16:00:00.000ZUTC time when the row was processed.

KVS output and summary

OUTPUT has schemaVersion (integer, 1), status (string), items (array of the same Dataset records) and summary (the RUN_SUMMARY object). None of these keys is null.

RUN_SUMMARY fieldType / empty valueMeaning / example
schemaVersioninteger1, contract version.
statusstringcomplete, partial, not_found or error.
errorCodestring or nullInput error such as INVALID_SITE_URLS; source errors are in outcomes.
stopReasonstring or nullRun-wide stop, such as RESULT_LIMIT, REQUEST_LIMIT, TIME_LIMIT, CANCELLED, CHARGE_LIMIT or TOTAL_BYTES_LIMIT.
rowsintegerSaved content row count; equals Dataset length and OUTPUT.items length.
requestsintegerAttempted HTTP requests, including redirects and retries.
retriesintegerRetried temporary failures.
responseBytesintegerCumulative serialized JSON response bytes; transport also caps raw response bytes.
skippedProtectedintegerPrivate, non-published or protected records returned by a source and skipped.
skippedOtherTypesintegerCustom content types skipped, such as podcast records in a posts endpoint.
duplicatesintegerRepeated site/type/ID records not saved twice.
elapsedMsintegerRuntime processing duration in milliseconds.
outcomesarrayOne result for each chosen site/type.

Each outcome has sourceUrl and contentType strings, status string, errorCode string or null, rows and pages integers, plus total and totalPages integers or null. Totals are source headers and can include source records outside the supported types. Missing headers stay null. Example: posts with status=partial, errorCode=PAGE_LIMIT, rows=2, pages=1.

Pricing

Pay per event:

  • Start: $0.0045 per GB of Actor memory, with at least one start event. The default 512 MB has one event.
  • Saved record: $0.0019 for each unique post or page saved to the Dataset.
  • Platform usage: charged to you by Apify separately. This includes compute, storage and traffic.

A valid empty run or search with no matches has the start charge and platform usage, with no saved-record charge. Failed, partial or cancelled runs still have the start charge and charges for records already saved. The Actor does not charge for a skipped type, duplicate, summary or source error. Dataset writes and charging are separate services; if a write or charge acknowledgement is lost, the run stops and does not retry that row. Inspect the Dataset and summary before repeating a failed run.

Saved records, default memoryEvent chargeExtra
0$0.0045Apify platform usage
1$0.0064Apify platform usage
10$0.0235Apify platform usage
100$0.1945Apify platform usage
1,000$1.9045Apify platform usage

The default maximum event cost per run is $2. You can set a lower cost limit in run options, if it is at least the start fee. A charge limit stops new saves and gives partial. The event limit is not a fixed total invoice: platform usage is separate. Higher memory increases start events. The runtime caps remain in place.

Use cases

JobInputUseful fieldsNext step
Content migrationChoose posts and pagescontent.rendered, title.rendered, slug, linkExport JSON for your migration tool.
SEO content listAdd a site and small limitid, titleText, link, date, categoriesExport CSV for review.
Text collectionChoose posts and optional searchcontentText, excerptText, sourceUrlRead Dataset records in your text workflow.

Schedules and repeat runs

You can create a schedule in Apify Console using the same input. Each run is a new snapshot with normal charges. There is no stored change state, new-only mode or unchanged discount. Use sourceUrl + type + id and modified_gmt to compare exports in your own system. A missing record in a bounded sample does not prove that the source deleted it.

API, MCP and integrations

Use the Apify API to POST the same input to acts/cliqtomedia~wordpress-posts-pages-scraper/runs. Add your API token in an Authorization header in your own application. Keep it out of shared URLs and screenshots. Set memory, timeout and maximum event charge in run options. After the run, read the default Dataset and KVS records.

For an agent workflow, the Apify MCP server can call the Actor with the same input. Pass link, titleText or contentText from each Dataset row to the next step.

The Dataset can be exported as JSON or CSV. In a Make or Zapier workflow, start the Actor with siteUrls, wait for completion, check RUN_SUMMARY.status, then read the Dataset rows. Check partial before treating the result as a full export.

Limits and partial results

The result cap is 1,000 saved records per run. A live WordPress News export returned 1,000 supported posts at 512 MB. This proves that sample, not every WordPress site. Sources can change, block cloud IPs, disable REST API routes or return large content.

Runtime caps: 100 source HTTP attempts including redirects and retries; about 5 minutes of source processing; 15 seconds per request or DNS lookup; 3 redirects per request; 8 MiB per HTTP response; 64 MiB cumulative serialized JSON responses; 1 MiB per HTML field. Requests are sequential with a delay. A large or slow response can end the run before its result cap.

complete means the selected collections were exhausted, including a valid empty result. partial means a cap, cancellation, missing taxonomy or failed collection left part of the result incomplete. not_found means all selected REST routes returned 404. error means input, access, network or parsing failed without usable rows. Error and not_found runs are marked FAILED by Apify; partial runs can be SUCCEEDED but must still be checked in KVS.

HTML is returned as data. It can contain source forms, public transient fields and scripts. Plain text skips scripts/styles but is not a visual copy of the page. Dates keep WordPress's meaning; the Actor does not guess a site's timezone. Source values can change between page requests. It does not provide a point-in-time database backup or resume a cancelled run.

Read the WordPress pagination guide for the source page and total-header rules.

Troubleshooting

SymptomPossible reasonCheck and next action
0 rows, completeA valid collection is empty or search has no matchesCheck search and selected types. Remove search for a small new run.
0 rows, errorNon-WordPress HTML, denied REST API or malformed JSONCheck outcomes.errorCode. Use the WordPress installation root and verify its public REST API.
not_foundBoth supported REST route formats return 404Check the site root or subdirectory. This Actor cannot enable the API.
Some rows, partialA limit, missing terms or one failed siteCheck row extractionStatus and outcomes. Increase page/result caps only within the allowed range.
HTTP_429 or HTTP_5xxSource rate limit or server problemThe Actor retries temporary failures up to twice. Increase requestDelayMs or try a small run later. Long Retry-After values stop with a clear code.
UNSAFE_ADDRESS or CROSS_SITE_REDIRECTPrivate address or another destination hostUse a public site root. Private addresses and unrelated redirect hosts are rejected.
RESPONSE_TOO_LARGE or CONTENT_TOO_LARGEThe source payload exceeds a size limitLower perPage for response size. A single oversized field remains unsupported.
PAGE_LIMIT or RESULT_LIMITMore source records exist than requestedThe result is a bounded sample. Increase the matching cap to read more.
REPEATED_PAGEThe source returned the same records againCheck the source API pagination. The Actor stops rather than collecting duplicates forever.

FAQ

Do I need a WordPress login?

No. The source API must be public. The Actor does not accept passwords or cookies.

Can it collect private posts or drafts?

No. It asks for publish in the public view and skips protected or non-published records.

Does it work on every WordPress site?

No. It needs a reachable core REST API on that site. Some hosted sites, plugins and firewalls change or block the API.

Is an empty run free?

No. It has the start event and Apify platform usage, but no saved-record event.

Can it collect all content without a limit?

No. Each run has explicit result, page, time, request and size limits. Check the summary before using an export.

Are category and tag names always available?

No. IDs can be present while embedded names are missing. Those values stay null and extractionStatus is partial. Standard pages have empty taxonomy arrays.

RSS & Atom Feed Reader / Monitor — read a feed and track feed item changes when a feed fits your source better.

Support

Open the Actor's Issues tab. Include the run ID, content type and safe error code. Do not send API tokens, passwords or private source content.