Rotten Tomatoes API endpoint
Returns Rotten Tomatoes movie reviews, newest first. All four `type` values return the full review feed in one request: each review carries a stable `id`, ISO `created_at`/`updated_at` timestamps, the critic identity and the original article URL, and the list is pageable `limit` reviews at a time: pass `data.page_info.end_cursor` back as `after` for the next page and keep `limit` the same while paging. `data.transport` is `feed_api` for that path. A title with no reviews yet, or a top-critics or audience list that is still empty, returns 200 with an empty `reviews` array. If the feed cannot be read the service loads the movie's own review page the way a visitor's browser does and reads the list that page receives (`transport: browser_render`, slower, at most five pages); if that also fails for the first page, the movie page's embedded sample of about 6 reviews is served with `render_error` set (`transport: public_page`) and the call is not charged. `data.subject.kind` is `movie`, and `data.movie` remains present for compatibility. `data.fetched_at` and the `X-Cache` and `X-Availability-Last-Success-*` response headers show how fresh the data is. Pass exactly one of `path` or `url`. Supported `type` values are `critics`, `top-critics`, `audience`, and `verified-audience`.
/rottentomatoes/movie/reviewsQuery parameters:
path: Rotten Tomatoes movie path, for example /m/inception.url: absolute https://www.rottentomatoes.com movie URL.type: review type. Allowed values: critics, top-critics, audience,
verified-audience.limit: reviews per page. Defaults to 10; maximum 20. A page holds limit
reviews, or fewer at the end of a list.after: pagination cursor. Pass data.page_info.end_cursor from the previous
response and keep limit the same on every page of one walk. A critic cursor
is a page index encoded as base64 (MQ== is page 2), so it points at a position
of index × limit reviews: changing limit between pages repeats or skips
reviews. Audience cursors are opaque keyset values and should be passed back
unchanged. The feed can serve up to 500 reviews; the browser fallback is capped
at five pages (100 reviews at the maximum page size). Invalid cursors are
rejected before upstream work.data.transportRotten Tomatoes serves each review list as a JSON feed. The service reads that feed directly and keeps the page-render and embedded-sample paths as fallbacks, so a caller gets the same response shape whichever path served it.
data.subject identifies what the feed is about. Its kind is one of
movie, season, episode, critic or publication; this endpoint sets movie. The
movie field remains present for compatibility. (The
season, episode and critic kinds belong to the dedicated
/rottentomatoes/season/reviews, /episode/reviews and /critic/reviews
endpoints.)data.transport is feed_api in the normal case, for all four type values.
It is one request per page: the reviews are newest-first, each has a stable
id, ISO created_at/updated_at timestamps, the critic identity and the
original article URL, and data.page_info carries has_next_page and
end_cursor. audience and verified-audience are served from the same feed,
so a verified-audience response is a full paginated list, not a six-review
sample. A title with no reviews yet, or a top-critics, audience or
verified-audience list that is still empty, is a real answer: the response is
200 with reviews: [] and has_next_page: false, charged as a normal call.data.transport is browser_render when the feed could not be read and the
movie's own review page could: the service loads the page the way a visitor's
browser does, lets that page request the list itself, and reads what the page
receives. Nothing is generated or replayed outside the page. Those responses
also carry data.render. The browser path is bounded to page 5 (100 reviews),
because every page beyond the first costs a click.data.transport is public_page as the last resort: for a page-0 request whose
feed and render both failed, the response holds the about-six reviews the movie
page embeds, has no cursor, and sets data.public_page_derived to true.transport: public_page, and
fills data.render_error with the reason. A request with after has no
fallback, because the public page cannot supply another page, and returns an
upstream error instead.Notable response behaviour:
data.render is present for browser_render responses and records how many distinct review
pages were loaded, how many "Load More" steps were needed, and the total time in milliseconds. It
is an audit record, not a cache age. feed_api responses have no render block.data.reviews_api_url is the review-list request on the Rotten Tomatoes website
that corresponds to the requested page. It identifies the page; it is not
necessarily the request that served the response, and it cannot be fetched by
an ordinary HTTP client.data.source_url is the public review page for the requested list, for example
https://www.rottentomatoes.com/m/clayface/reviews/all-critics.created_at is the review's upstream creation time in ISO 8601 (for example
2026-10-28T22:12:45.000Z) for feed_api and browser_render responses. It is
not a record of when a review became visible on the site, and it is not the
display text on the page. For public_page responses created_at is only what
the page prints, which for older films is a calendar date (Mar 20, 2024) and
for a film in its first day or two is relative text such as 2 hrs ago.updated_at is set when a review was edited after it was created, and
status is the upstream review status (normally ACTIVE).rating and rating_label are the audience star rating: rating is the
numeric value (4.5) and rating_label the upstream label (STAR_4_5).
Critic reviews carry original_score instead when the critic published a
score (4/5, B+).publication_review_url links to the original article. Corrections and
removals are not reported.critics, top-critics, audience, and
verified-audience are rejected before upstream IO.data.fetched_at is the UTC time, to the second, when the Rotten Tomatoes
data behind the response was fetched. A cached response keeps its original
time.X-Availability-Last-Success-At response header
(RFC 3339, sub-second), and X-Availability-Last-Success-Age-Seconds gives
the age of the data in whole seconds. X-Cache is miss for a live fetch
and hit for a reused response.transport is public_page and render_error says why) is not
charged. That includes a reused copy of such a response. A feed_api or
browser_render response is charged as usual.X-Availability-Mode: stale and X-Stale-Cache: hit.feed_api response reads the movie page and then the review list, and
normally returns in a few seconds (4 to 8 seconds measured). A browser_render response loads a real page, so it is much slower,
about 16 seconds for the first page and about 43 seconds for the fifth (each
deeper page takes extra time). The first call after a quiet period of about
five minutes takes roughly 5 to 8 seconds longer. Concurrent callers may wait
briefly, bounded by their own request deadline.fetched_at is the latest the data could have been captured, not the time a
review was published.| Field | Filled in, of 6 checked | Values in the sample |
|---|---|---|
| type | 6 | |
| display_name | 6 | |
| publication | 6 | |
| created_at | 6 | |
| review | 6 | median 116 characters |
| score_sentiment | 6 | |
| top_review | 6 | true in 0 of 6 |
| top_critic | 6 | true in 1 of 6 |
| top_publication | 6 | true in 3 of 6 |
| tomatometer_approved | 6 | true in 3 of 6 |
| publication_approved | 6 | true in 4 of 6 |
| verified | 6 | true in 0 of 6 |
| super_reviewer | 6 | true in 0 of 6 |
| has_spoilers | 6 | true in 0 of 6 |
| has_profanity | 6 | true in 0 of 6 |
| critic_url | 6 | rottentomatoes.com |
| publication_review_url | 6 | thetimes.co.uk and 5 other hosts |
| original_score | 2 |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| path | string | No | Rotten Tomatoes movie path | /m/inception | |
| url | string | No | Absolute https://www.rottentomatoes.com movie URL | https://www.rottentomatoes.com/m/inception | |
| type | string | No | Review type: critics, top-critics, audience, verified-audience Allowed values: critics, top-critics, audience, verified-audience. | critics | |
| limit | integer | No | Reviews per page, default 10, max 20. Keep it the same on every page of one walk: the critic cursor is a page index times this value. | 10 | |
| after | string | No | Pagination cursor: pass data.page_info.end_cursor from the previous response. Critic cursors are base64 page indexes; audience cursors are opaque keyset values that should be passed back unchanged. The feed can serve up to 500 reviews; browser fallback is capped at five pages. Invalid cursors are rejected before upstream work. | MQ== | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/rottentomatoes/movie/reviews?type=critics&limit=10" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"subject": {
"kind": "movie",
"path": "/m/clayface",
"url": "https://www.rottentomatoes.com/m/clayface",
"title": "Clayface",
"ems_id": "d5639ed5-2dfe-44a3-8ed2-1cb3ea99855f",
"media_type": "movie"
},
"movie": {
"title": "Clayface",
"path": "/m/clayface",
"url": "https://www.rottentomatoes.com/m/clayface",
"ems_id": "d5639ed5-2dfe-44a3-8ed2-1cb3ea99855f",
"media_type": "movie"
},
"type": "critics",
"limit": 20,
"transport": "feed_api",
"source_url": "https://www.rottentomatoes.com/m/clayface/reviews/all-critics",
"reviews_api_url": "https://www.rottentomatoes.com/napi/rtcf/v1/movies/d5639ed5-2dfe-44a3-8ed2-1cb3ea99855f/reviews?type=critic&pageCount=20",
"fetched_at": "2026-10-29T02:31:40Z",
"page_info": {
"has_next_page": true,
"end_cursor": "MQ=="
},
"reviews": [
{
"id": "103175211",
"type": "critic",
"display_name": "Mark Kermode",
"publication": "Kermode and Mayo's Take",
"created_at": "2026-10-28T22:12:45.000Z",
"updated_at": "2026-10-28T22:12:45.000Z",
"status": "ACTIVE",
"language": "English",
"review": "A representative review excerpt.",
"score_sentiment": "POSITIVE",
"top_review": true,
"top_critic": true,
"tomatometer_approved": true,
"critic_url": "https://www.rottentomatoes.com/critic/mark-kermode",
"critic_vanity": "mark-kermode",
"publication_review_url": "https://www.youtube.com/watch?v=example"
}
],
"public_page_derived": false
}
}Request schema
No body schema
Response schema
#/definitions/rottentomatoes.reviewsResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | rottentomatoes.ReviewsResponse | No | ||||
| data.fetched_at | string | No | 2026-06-07T14:46:16Z | UTC time, to the second, when the Rotten Tomatoes page behind this response was fetched. A cached response keeps its original time. | ||
| data.limit | integer | No | 10 | |||
| data.movie | object | No | Movie summary, for movie feeds only. Kept for existing callers; prefer subject for new integrations. | |||
| data.movie.ems_id | string | No | afbf1c81-1bfe-3996-9cbc-2e1be23d1f61 | |||
| data.movie.media_type | string | No | Movie | |||
| data.movie.path | string | No | /m/inception | |||
| data.movie.title | string | No | Inception | |||
| data.movie.url | string | No | https://www.rottentomatoes.com/m/inception | |||
| data.page_info | object | No | Whether more reviews follow this page, and the cursor to request them. | |||
| data.page_info.end_cursor | string | No | Mjk= | Cursor of the last item on this page. Pass it as `after` to get the next page. | ||
| data.page_info.has_next_page | boolean | No | true | Whether more items follow this page. | ||
| data.page_info.has_previous_page | boolean | No | true | Whether items precede this page. | ||
| data.page_info.start_cursor | string | No | MA== | Cursor of the first item on this page. | ||
| data.public_page_derived | boolean | No | true | True when the reviews came from the public page's embedded sample rather than from the gated critic-review feed. | ||
| data.render | object | No | Browser render audit facts. Present only for `browser_render`. | |||
| data.render.load_more_clicks | integer | No | 0 | "Load More" steps needed to reach the requested page. | ||
| data.render.pages_fetched | integer | No | 1 | Number of distinct review pages that were loaded. | ||
| data.render.total_ms | integer | No | 18432 | Total wall time the render took, in milliseconds. | ||
| data.render_error | string | No | Why a browser render that was attempted did not produce the response, when a public-page sample was served instead. | |||
| data.reviews | array | No | ||||
| data.reviews[].created_at | string | No | 2024-04-11T23:40:16.000Z | |||
| data.reviews[].critic_url | string | No | https://www.rottentomatoes.com/critic/danilo-castro | |||
| data.reviews[].critic_vanity | string | No | danilo-castro | Upstream critic vanity path, the last segment of critic_url. | ||
| data.reviews[].display_name | string | No | Danilo Castro | |||
| data.reviews[].encrypted_critic_id | string | No | Upstream encrypted critic identifier. | |||
| data.reviews[].encrypted_publication_id | string | No | Upstream encrypted publication identifier. | |||
| data.reviews[].has_profanity | boolean | No | false | |||
| data.reviews[].has_spoilers | boolean | No | false | |||
| data.reviews[].id | string | No | 102903742 | |||
| data.reviews[].language | string | No | English | Language the review was written in, such as `English`. | ||
| data.reviews[].media | object | No | Title the review is about. Present on critic-feed responses (a critic reviews many titles) and omitted elsewhere. | |||
| data.reviews[].media.path | string | No | /m/inception | Rotten Tomatoes path of the reviewed title. | ||
| data.reviews[].media.poster_url | string | No | Poster image URL of the reviewed title. | |||
| data.reviews[].media.title | string | No | Inception | Title of the reviewed movie or TV series. | ||
| data.reviews[].media.url | string | No | https://www.rottentomatoes.com/m/inception | Absolute Rotten Tomatoes URL of the reviewed title. | ||
| data.reviews[].original_score | string | No | 9/10 | |||
| data.reviews[].publication | string | No | Next Best Picture | |||
| data.reviews[].publication_approved | boolean | No | true | |||
| data.reviews[].publication_id | string | No | Upstream publication identifier. | |||
| data.reviews[].publication_review_url | string | No | https://nextbestpicture.com/inception/ | |||
| data.reviews[].rating | number | No | 4.5 | |||
| data.reviews[].rating_label | string | No | STAR_4_5 | |||
| data.reviews[].review | string | No | ||||
| data.reviews[].scheduled_at | string | No | 2026-10-21T19:11:02.000Z | Upstream scheduling time of the review, when provided. | ||
| data.reviews[].score_sentiment | string | No | POSITIVE | |||
| data.reviews[].status | string | No | ACTIVE | Upstream review status, such as `ACTIVE`. | ||
| data.reviews[].super_reviewer | boolean | No | false | |||
| data.reviews[].tomatometer_approved | boolean | No | true | |||
| data.reviews[].top_critic | boolean | No | false | |||
| data.reviews[].top_publication | boolean | No | false | |||
| data.reviews[].top_review | boolean | No | false | |||
| data.reviews[].type | string | No | critic | |||
| data.reviews[].updated_at | string | No | 2026-10-28T22:40:02.000Z | Time the review was last edited upstream, when it differs from created_at. | ||
| data.reviews[].verified | boolean | No | false | |||
| data.reviews_api_url | string | No | https://www.rottentomatoes.com/napi/rtcf/v1/movies/afbf1c81-1bfe-3996-9cbc-2e1be23d1f61/reviews?type=critic&pageCount=10 | |||
| data.source_url | string | No | https://www.rottentomatoes.com/m/inception/reviews/all-critics | |||
| data.subject | object | No | Subject of the feed: a movie, TV season, TV episode or critic. | |||
| data.subject.ems_id | string | No | 71374db9-1350-30fa-b30a-d3f623bbdfc4 | Rotten Tomatoes' own unique id of the subject, when it has one. | ||
| data.subject.kind | string | No | movie, season, episode, critic, publication | season | Kind of subject: `movie`, `season`, `episode`, `critic` or `publication`. | |
| data.subject.media_type | string | No | TvSeason | Kind of title, such as `TvSeason`. | ||
| data.subject.path | string | No | /tv/breaking_bad/s01 | Rotten Tomatoes path of the subject. | ||
| data.subject.title | string | No | Breaking Bad: Season 1 | Display title of the subject, when known. | ||
| data.subject.url | string | No | https://www.rottentomatoes.com/tv/breaking_bad/s01 | Rotten Tomatoes page URL of the subject. | ||
| data.transport | string | No | feed_api, browser_render, public_page | feed_api | How the reviews were read. `feed_api` is the review feed's own JSON API, which is newest-first, carries review ids and ISO timestamps and is not bounded by the page's click depth. `browser_render` is the same feed read from the review page's own requests in a real browser. `public_page` is the embedded sample on the public movie page. | |
| data.type | string | No | critics | |||
| msg | string | No | OK |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 404 | Not Found | #/definitions/app.Response |
| 429 | Too Many Requests | #/definitions/app.Response |
| 500 | Internal Server Error | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/rottentomatoes/movie/reviews?type=critics&limit=10" \
-H "x-api-key: $CRAWLORA_API_KEY"