# Untappd Beer Reviews Scraper (`automation-lab/untappd-beer-reviews`) Actor

Extract recent public Untappd beer reviews and check-ins from supplied beer URLs, with ratings, comments, authors, timestamps and stable IDs for recurring beverage reputation analysis.

- **URL**: https://apify.com/automation-lab/untappd-beer-reviews.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 item extracteds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Untappd Beer Reviews Scraper

Collect recent public **Untappd reviews** for selected beers as one structured row per check-in. Breweries, beverage analysts, and research teams can refresh ratings and tasting comments for reputation analysis, then compare snapshots in their own spreadsheet or data pipeline.

Supply canonical beer page URLs. The Actor reads the anonymous public feed and returns stable check-in IDs, beer and brewery names, public author information, ratings, optional comments, UTC timestamps, and canonical links. It does not retrieve full history or private activity.

### Who is it for?

Breweries can collect observed public feedback for their beers. Beverage researchers can compare ratings and comments across a selected catalog. Data teams can append timestamped snapshots to existing analysis workflows without treating a recent feed as historical completeness.

### Why use this Actor?

- Join recurring snapshots by stable check-in ID instead of matching text.
- Keep unrated check-ins and comments without inventing missing values.
- Receive one flat review row, rather than a beer-level summary containing nested activity.
- Cap unique records globally across your selected beers.
- Detect upstream failures through honest failed-run status, not a successful empty challenge page.

The public feed is a recent window, not an archive. Scheduling more frequently can reduce gaps but cannot guarantee complete capture.

### Getting started

1. Open the input editor.
2. Paste one or more canonical Untappd beer URLs into **Beer page URLs**.
3. Set **Maximum review records per run** if needed.
4. Start the Actor and wait for a successful finish.
5. Open the Reviews dataset and export JSON, CSV, Excel, or another supported Apify format.

Example input:

```json
{
  "beerUrls": [
    "https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499"
  ],
  "maxItems": 100
}
```

### Input parameters

| Field | Behavior |
|---|---|
| `beerUrls` | Required array of 1–10 canonical HTTPS `untappd.com/b/<slug>/<numeric-id>` strings. No queries, fragments, login URLs, brewery URLs, or search routes. |
| `maxItems` | Global unique check-in cap; integer 1–200, default 100. Zero and unlimited are unsupported. |

URLs are processed sequentially in input order. Duplicate canonical URLs, including a trailing-slash variant, are fetched only once. Check-in IDs are deduplicated globally. Once the record or billing limit is reached, later URLs are not fetched. Fewer records may be available than requested.

There are no search filters, keyword matching, historical date ranges, or stored cross-run state. Unknown input fields are rejected rather than ignored. US residential HTTP routing is automatic; users do not need to supply proxy credentials.

### Untappd reviews output

| Field | Meaning |
|---|---|
| `checkinId` | Stable check-in identifier, stored as a string. |
| `beerId` | Beer identifier from the supplied URL. |
| `beerName` | Beer name on the check-in. |
| `breweryName` | Public brewery name, or null. |
| `authorName` | Public display name. |
| `authorHandle` | Public handle from the check-in link. |
| `rating` | Numeric score from 0 to 5, or null when absent. |
| `comment` | Public tasting/review text, or null when absent. |
| `timestamp` | Source check-in timestamp normalized to UTC ISO 8601. |
| `checkinUrl` | Canonical public check-in URL. |
| `beerUrl` | Beer link exposed on the record. |
| `sourceUrl` | Supplied beer page used to collect the row. |
| `scrapedAt` | UTC extraction timestamp. |

A check-in need not contain text or a rating. Missing values stay null; zero ratings are not treated as missing. The Actor excludes unrelated beer entries rather than assigning them to the requested beer.

### Example output

This illustrates the tested record structure with anonymized author and check-in identifiers:

```json
{
  "checkinId": "1234567890",
  "beerId": "4499",
  "beerName": "Pliny the Elder",
  "breweryName": "Russian River Brewing Company",
  "authorName": "Example Reviewer",
  "authorHandle": "exampleuser",
  "rating": 4.75,
  "comment": null,
  "timestamp": "2026-10-26T05:18:15.000Z",
  "checkinUrl": "https://untappd.com/user/exampleuser/checkin/1234567890",
  "beerUrl": "https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499",
  "sourceUrl": "https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499",
  "scrapedAt": "2026-10-26T06:00:00.000Z"
}
```

The default dataset contains the review records. The output tab also links to `SUMMARY`, a per-run JSON record with page, request, response-byte, and saved-record counts.

### Coverage and limits

Only the initial recent anonymous public feed is collected. The number of visible check-ins varies by beer and source behavior; a tested page exposed 20 target-beer records. There is no pagination beyond that public snapshot, no full-history guarantee, and no access to login-only or private data.

Each unique beer requires a page request even when `maxItems` is small. The Actor does not download images or other browser assets. It uses at most three fresh residential identities per page, then stops with an error if the source still rejects access. A successful small snapshot does not establish universal access to every beer.

### How much does it cost to collect Untappd beer reviews?

The Actor uses pay-per-event pricing: a **$0.02 one-time start charge** plus a charge for each unique public review saved. Empty pages, rejected rows, and duplicates have no review-event charge. The start charge may still apply when a requested beer fails upstream.

| Apify spend tier | Price per review |
|---|---:|
| FREE | $0.00092 |
| BRONZE | $0.0008 |
| SILVER | $0.000624 |
| GOLD | $0.00048 |
| PLATINUM | $0.00048 |
| DIAMOND | $0.00048 |

For BRONZE, 1 saved review is approximately $0.0208, 20 reviews $0.036, and 100 reviews across multiple beers $0.10, including one start charge. FREE examples are $0.02092, $0.0384 and $0.112 respectively. These are event-price estimates, not guaranteed invoices; actual source volume and spending caps determine how many records are saved. Spend tiers follow Apify's qualifying monthly Store spend, not this Actor's record volume. Platform usage by this Actor is included in its event price. A higher record limit cannot force the source to expose additional reviews. Use Apify's run spending cap for additional billing control.

### Integrations and recurring analysis

Schedule runs in Apify for recurring snapshots. Append records to Google Sheets, a database, or your warehouse, and deduplicate on `checkinId`. Group by beer and time to study observed ratings and comments. Preserve `scrapedAt` to distinguish collection time from the check-in timestamp.

Use Make, Zapier, n8n, webhooks, or the Apify API to fetch a successful run's dataset. Store long-term history downstream: this Actor does not maintain an archive, compare snapshots, or send sentiment/change alerts. Review source coverage before interpreting missing rows as deleted reviews.

### API examples

Use an Apify token from an environment variable. Keep tokens out of shared URLs and source control.

#### cURL

```bash
curl -X POST \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  'https://api.apify.com/v2/acts/automation-lab~untappd-beer-reviews/runs' \
  -d '{"beerUrls":["https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499"],"maxItems":100}'
```

Retain the returned run ID. Read `/v2/actor-runs/RUN_ID` until terminal with bounded backoff, then fetch `/v2/datasets/DATASET_ID/items` using its `defaultDatasetId`. Do not start a second run merely to check the first.

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/untappd-beer-reviews').call({
  beerUrls: ['https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499'],
  maxItems: 100,
});
if (run.status !== 'SUCCEEDED') throw new Error(`Run ${run.id}: ${run.status}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 100 });
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/untappd-beer-reviews').call(run_input={
    'beerUrls': ['https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499'],
    'maxItems': 100,
})
if run['status'] != 'SUCCEEDED':
    raise RuntimeError(f"Run {run['id']}: {run['status']}")
print(client.dataset(run['defaultDatasetId']).list_items(limit=100).items)
```

### MCP use

Select this Actor explicitly in your MCP client:

```bash
claude mcp add --transport http apify \
  'https://mcp.apify.com?tools=automation-lab/untappd-beer-reviews'
```

For Claude Desktop, Cursor, or VS Code with an HTTP-capable MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/untappd-beer-reviews"
    }
  }
}
```

Configure authentication using your client's Apify support. Discover actual tool names and input schemas with `tools/list`. Actor selection also includes run and storage tools; it does not expose exactly one tool. A private or not-yet-published Actor may not be discoverable.

Example prompt: “Collect up to 20 recent public check-ins for this canonical beer URL, then show ratings and comments with links. Do not infer full historical coverage.”

Start once and retain the run ID, status, and storage IDs. They are metadata, not result rows. If still running, check the same run with 2, 4, then 8-second delays capped at 10 seconds and a 120-second total deadline. Set client request timeouts above the selected server wait plus transport margin. Recover the known run after a timeout instead of restarting; if the ID is unknown, report uncertainty. At deadline, report pending with the run ID and stop. Failed-run rows are partial.

After success, read bounded dataset pages: for example 20 source rows per page, at most 100 rows or 64 KiB of serialized result content admitted to model context, whichever comes first. Enforce bytes host-side before model injection; disclose omitted or oversized content. If your client cannot intercept responses, do not claim a hard byte guarantee. Track source offsets, report truncation and the continuation offset, and keep full exports outside model context. Discovery caching and token savings depend on the client; no numerical savings are promised.

### FAQ and troubleshooting

**The run fails with a feed/challenge error.** The source could not provide recognizable public records within the bounded attempts. Verify the URL in an anonymous browser. Do not interpret a challenge as “no reviews.”

**The run returns fewer rows than `maxItems`.** This cap is not a target. The source exposes only a recent window. Multiple URLs may overlap, and stable IDs are deduplicated.

**One beer works and another fails.** A later error makes the whole run FAILED; any already saved rows are partial. Inspect the log before using them as a complete snapshot. Correct malformed or unavailable URLs instead of scheduling blind repeats.

**Can I search by beer name or collect brewery history?** No. Supply canonical beer page URLs. Search, full history, private feeds, and authenticated APIs are outside this product's scope.

### Legality and responsible use

Collect only public data you are entitled to process. Respect applicable law, source terms, privacy obligations, and downstream retention requirements. Public visibility does not grant unrestricted reuse rights. This Actor is independent of Untappd and is not an official Untappd API.

### Data handling and diagnostic privacy

No AI models process user inputs or review records. Apify supplies compute, storage and residential proxy transport, paid by us through the event price. Public author names and handles appear only in the requested review output, not the request logs. Source pages are parsed in memory; no cookies or raw HTML are stored by the Actor. Your Apify account's storage-retention settings control datasets, run input, summaries and logs; delete these through Console or API when no longer needed. Downstream exports have their own retention. Ask through the Actor's Issues tab for bugs, questions, or data-handling help.

Failed operations send sanitized diagnostic input, exceptions, and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL query strings are removed; reports are retained for 30 days. Do not put secrets or private content in beer URLs.

### Related workflows

This is a standalone recent-review specialist. No unpublished Untappd Actor is recommended as a supported integration. For broader analyses, combine its flat dataset with your own licensed product catalog and retain provenance for each source.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/untappd-beer-reviews/changelog.md

# Actor input Schema

## `beerUrls` (type: `array`):

Supply 1–10 canonical HTTPS untappd.com/b/<slug>/<numeric-id> URLs, without queries or fragments. URLs are processed in input order; duplicate canonical URLs are fetched once. Only each page's recent public feed is read, without pagination.

## `maxItems` (type: `integer`):

Global maximum of unique check-in records across all supplied beers, after ID deduplication and excluding unrelated feed entries. Default 100; allowed 1–200. Zero/unlimited is unsupported. The source may expose fewer records; later URLs are not fetched once this limit or your billing limit is reached.

## Actor input object example

```json
{
  "beerUrls": [
    "https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499"
  ],
  "maxItems": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Unique public check-in records.

## `summary` (type: `string`):

Pages, requests, response bytes, and saved record count.

# 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 = {
    "beerUrls": [
        "https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/untappd-beer-reviews").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 = {
    "beerUrls": ["https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/untappd-beer-reviews").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 '{
  "beerUrls": [
    "https://untappd.com/b/russian-river-brewing-company-pliny-the-elder/4499"
  ],
  "maxItems": 20
}' |
apify call automation-lab/untappd-beer-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/untappd-beer-reviews"
        }
    }
}
```

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/C7V3jSslu6jreqkwt/builds/CkJ1wcoNFuEjfu1Oc/openapi.json
