Tumblr Scraper - Blog & Tag Posts, Notes & Media avatar

Tumblr Scraper - Blog & Tag Posts, Notes & Media

Pricing

from $2.00 / 1,000 actor run starteds

Go to Apify Store
Tumblr Scraper - Blog & Tag Posts, Notes & Media

Tumblr Scraper - Blog & Tag Posts, Notes & Media

Tumblr scraper for blogs and tag pages: give it a blog name or a tag and get one row per post with text, tags, posting date, media URL and all four engagement counts (notes, likes, reblogs, replies). Tag pages work as a public search across the whole site. Export JSON or CSV; no API key.

Pricing

from $2.00 / 1,000 actor run starteds

Rating

0.0

(0)

Developer

SR

SR

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

13 days ago

Last modified

Share

This Tumblr scraper reads any public blog page or tag page and returns one row per post: the post text, its tags, when it was posted, what media it carries, and all four engagement counts Tumblr publishes (notes, likes, reblogs and replies). Give it blog names like staff, tags like #photography, or the links themselves. No API key, no login, no app registration.

Use it when you want Tumblr data as rows instead of screenshots: fandom and trend research on a tag that is live across the whole site, brand monitoring on a schedule, creator research on a blog you name yourself, or an archive of post text with the media URL beside it. Tag pages are the practical search surface here, because Tumblr shows no keyword search to a visitor who is not signed in.

What the Tumblr scraper returns

  • One dataset row per post, with the long-standing field names and JSON types kept intact, so an existing consumer keeps working.
  • All four engagement counts side by side: note_count, like_count, reblog_count, reply_count.
  • Post text, Tumblr's own summary and the tag list, so a row is usable for search and classification without a second request.
  • Media identified, not downloaded: media_type and media_url for the first non-text block of the post.
  • Reblog marking: is_reblog and parent_post_url, so an original and a redistribution of it can be told apart.
  • Provenance on every row: found_on (blog or tag), source (which blog or tag it came from), position in the run, and fetched_at.
  • Run summary and errors alongside the rows: posts per target, how many were reblogs, totals for notes and reblogs, and an error naming any blog or tag that could not be read.
  • Clean exports: download the dataset as JSON, CSV, Excel or XML, or read it through the Apify API.

Tumblr scraper input

FieldDefaultMeaning
targetsβ€”Blog names, blog links, or tags as #photography or a /tagged/ link
max_posts50Stop after this many posts across all blogs and tags (1–500)
max_targets20Stop after this many, counted after duplicates are removed (1–100)
attempts6How often to retry a page that comes back without the expected payload (1–15)
regionusTwo-letter country code the request should appear to come from

A link to a blog's own subdomain is rewritten to the path that works, because the subdomain itself refuses anonymous requests. Invalid items are reported as errors and skipped; the rest of the run continues. A string of comma- or newline-separated names is accepted the same way as a list.

max_posts is a ceiling across the whole run, not a per-target share. A blog page carries about 20 posts and a tag page about 10, so a blog and a tag at max_posts: 40 gives you 20 and 10 rather than 20 each. Raise it together with max_targets to widen a run.

The store's initial example asks for staff and #photography. Those are prefill values in the form, not defaults added to an API request: a request that omits targets has nothing to read and returns no rows. An input that runs both surfaces at once looks like this:

{
"targets": ["staff", "#photography"],
"max_posts": 60,
"max_targets": 20,
"attempts": 6,
"region": "us"
}

Tumblr scraper output

One dataset row per post. The fields match the long-standing schema so existing consumers keep working:

FieldTypeMeaning
post_idstringTumblr's id for the post
urlstringLink to the post (falls back to short_url)
short_urlstring | nullTumblr short link
blog_namestring | nullThe blog that posted it
blog_titlestring | nullThe blog's display title
blog_urlstring | nullThe blog's page
summarystring | nullTumblr's own one-line summary
textstring | nullThe post's words, assembled from its text blocks (capped at 5000 characters)
tagsstring[] | nullTags on the post
hashtagsstring[] | nullNormalised tags (lowercase, no #, deduplicated)
posted_atstring | nullWhen it was posted, UTC
note_countinteger | nullNotes, Tumblr's own rollup of all activity
like_countinteger | nullLikes
reblog_countinteger | nullReblogs
reply_countinteger | nullReplies
media_typestring | nullType of the first non-text block, such as image or video
media_urlstring | nullURL of that media
is_reblogbooleanTrue when the post is a reblog of another
parent_post_urlstring | nullThe post it reblogged
found_onstringblog or tag
sourcestringWhich blog or tag it came from
positionintegerPosition in the run
fetched_atstringWhen the row was collected, ISO 8601 UTC

This is a real row, collected from the #photography tag page on 7 October 2026:

{
"post_id": "798772056005148672",
"url": "https://www.tumblr.com/princesssokphanny/798772056005148672/a-once-in-a-lifetime-shot-the-moon-perfectly",
"short_url": "https://tmblr.co/ZcXgWSiLplFkiW00",
"blog_name": "princesssokphanny",
"blog_title": "Sokphanny Tith",
"blog_url": "https://www.tumblr.com/princesssokphanny",
"summary": "A once-in-a-lifetime shot β€” the moon perfectly framed by a rainbow. Caught at just the right time. 🌈 πŸŒ•",
"text": "A once-in-a-lifetime shot β€” the moon perfectly framed by a rainbow. Caught at just the right time. 🌈 πŸŒ•",
"tags": [
"aesthetic", "sky", "skies", "rainbow", "nature", "naturecore", "positivity",
"curators on tumblr", "pretty", "paradise", "moon", "whimsicore", "whimsical",
"fairycore", "grandmacore", "gardencore", "cottagecore", "cozycore",
"photography", "amazing photography", "sailor moon", "photo", "magic", "🌈",
"gay", "queer", "lgbtqia"
],
"hashtags": [
"aesthetic", "sky", "skies", "rainbow", "nature", "naturecore", "positivity",
"curators on tumblr", "pretty", "paradise", "moon", "whimsicore", "whimsical",
"fairycore", "grandmacore", "gardencore", "cottagecore", "cozycore",
"photography", "amazing photography", "sailor moon", "photo", "magic", "🌈",
"gay", "queer", "lgbtqia"
],
"posted_at": "2025-10-29T20:06:34Z",
"note_count": 206483,
"like_count": 129661,
"reblog_count": 75725,
"reply_count": 1097,
"media_type": "image",
"media_url": "https://64.media.tumblr.com/bd50af3b52c14255a0f7f3a8ca8aec3d/05f26ead8ff3139b-27/s2048x3072/374da9f750d79e98a0b799988ababb4ad5e5df95.jpg",
"is_reblog": false,
"parent_post_url": null,
"found_on": "tag",
"source": "photography",
"position": 1,
"fetched_at": "2026-10-07T12:00:00.000Z"
}

Seven posts came back from that one call, from seven different blogs.

The run summary records blogs and tags read, posts per target, how many were reblogs, and total notes and reblogs. Errors list blogs or tags that could not be read. A blog that does not exist still answers with a page and zero posts, so the run succeeds, delivers no rows, and records an error naming that blog β€” the same behaviour older consumers already expect.

Four counts, not one

Tumblr publishes four numbers per post and most tools report one of them. Notes is Tumblr's own rollup of everything that happened to a post. It is not a reliable sum of likes, reblogs and replies, and it is never recomputed here: the published value is used.

The distinction that matters on Tumblr is between likes and reblogs. A like means someone saw it. A reblog means someone put it in front of their own followers, which is how anything travels on this site. A post with 9,000 likes and 200 reblogs and one with 3,000 likes and 6,000 reblogs are very different posts, and a single engagement number hides which is which. That is why this Tumblr scraper returns all four counts side by side.

Tumblr offers no keyword search to a signed-out visitor. What it does offer is /tagged/<tag>, which is public and returns current posts carrying that tag from across the whole site, not from one blog.

Pass #photography or a /tagged/ link and that is what you get. Every row records found_on and source, so blog posts and tag results stay distinguishable in one table. That makes tag pages the practical search surface for creator and trend research.

Use cases

Fandom and trend research. Tag pages are where a topic is actually visible on Tumblr, and the reblog counts show what is spreading rather than what is merely being seen. Run a tag on a schedule and keep the rows; posted_at tells you when each one arrived.

Brand monitoring. Watch a brand or product tag the same way. New posts from blogs you have not seen before are the signal, and uniqueBlogs in the summary counts the distinct blogs a run came from.

Creator research. Reblogs against likes across a blog's recent posts is a better read on reach than a follower count, which Tumblr does not publish on these pages anyway. Name the blogs you follow and take the last fifty posts.

Content archiving. Post text, tags, media URL and dates in one table, with reblogs marked so originals can be separated from redistribution.

Training and classification data. text, summary and tags are plain text with the tags already attached, which is what a labelling or embedding pipeline wants without a second pass over the page.

What this Tumblr scraper does not cover

No follower counts. Tumblr does not publish them on these pages, so there is no follower column rather than an empty one.

No notes breakdown. The note count is a total; who liked and who reblogged is on a separate page per post and is not returned here.

No dashboard, likes or following. Those need an account and are not public.

No blog search by name. Tags are searchable, blogs are not: you name the blogs you want.

Only public blogs are readable. A blog that is hidden, deleted or explicit-only is reported by name rather than returned as an empty result. Counts move, so a run is a snapshot; the posting date is on every row. Media is identified rather than downloaded: media_url points at Tumblr's CDN.

How this Tumblr scraper compares

This actorOfficial Tumblr APIBrowser extensions and open-source scripts
SetupFill in a form or send JSONRegister an application and complete OAuth for most blog contentInstall, configure and maintain your own code
Login or API keyNoneRequiredDepends on the script
Blog pages and tag pages in one runYes, one targets listSeparate endpoints; no site-wide tag searchOne page at a time, by hand
Engagement countsnotes, likes, reblogs and replies on every rowTumblr's own published countsDepends on the script
ExportJSON, CSV, Excel, XML, APIJSON onlyWhatever you build
Cost$0.002 per run plus $0.0015 per delivered postFree, rate-limitedYour own time and upkeep

Other Tumblr actors in the Apify Store tend to do one job each β€” blog posts only, tags only, or media only. This one takes blogs and tags through a single targets list with one schema, so rows from a blog run and a tag run can be joined on post_id.

Pricing

  • Run start: $0.002 per run, charged once when the run begins, whether or not any posts are found.
  • Post: $0.0015 per delivered row.

Empty results cost nothing beyond the run start. A blog or tag that returns no posts does not generate post events. On the free plan each run delivers at most 10 posts; the same input is otherwise unchanged. A 1,000-post run therefore costs $1.50 plus the $0.002 start fee, and there are no compute-unit charges on top.

Limits and collection behavior

Tumblr decides how many posts a page exposes. A blog page carries about 20 posts and a tag page about 10, so max_posts is a ceiling rather than a promise: one blog target delivers about twenty rows whatever you ask for. Raise max_targets when you want more surfaces in the same run β€” each target contributes one page.

Pages that come back without the expected payload are retried up to attempts times. A run that cannot finish a page keeps the rows it already delivered and reports the rest through errors and the summary. Empty results, a blog that does not exist and a temporary upstream refusal all end as a successful, empty run with an explanation β€” never as a failed run that loses the rows you did get.

FAQ

Is this Tumblr scraper different from the official Tumblr API?

The official API needs an application registration and OAuth for most blog content, and it does not expose tag pages as a site-wide search. This Tumblr scraper reads the same public pages a signed-out visitor sees and returns rows without an API key.

Does it need a login or a browser?

No. Posts ship in the page's own state payload. A plain HTTPS fetch is enough; there is no headless browser and no session cookie.

What happens to a blog that does not exist?

A missing blog still returns a page with the state payload and zero posts. The run succeeds, delivers no rows, and records an error naming that blog. That is the same behaviour older consumers already expect.

Why is note_count not the sum of the other counts?

Because Tumblr's notes rollup includes activity the named counts do not break out, and it is not defined as their sum. The published note_count is returned unchanged alongside likes, reblogs and replies.

Can I search Tumblr for a keyword without an account?

Not directly β€” Tumblr hides keyword search behind a login. Search by tag instead: #photography or a /tagged/photography link returns current posts carrying that tag from across the whole site, which is the closest thing to a public Tumblr search there is.

Can I collect more than one page per blog?

A blog page carries about 20 posts and a tag page about 10. Raise max_posts and pass more targets to widen the run; each target contributes one page. For very large jobs the run continues with a cursor so a single request never has to hold every target at once.

Which targets are accepted?

Blog names (staff), blog links (https://staff.tumblr.com or https://www.tumblr.com/staff), and tags as #photography or https://www.tumblr.com/tagged/photography. Paths that are not blogs (tagged, explore, search, and so on) are rejected as input errors and skipped.

Are empty results charged?

Only the run start. Post charges follow rows actually delivered, so a run that finds nothing costs $0.002 and no more.