# HelloPeter Scraper \[$0.95/1K💰] | SA Reviews & TrustIndex (`ahmed_jasarevic/hellopeter-scraper`) Actor

Scrape HelloPeter, South Africa's biggest review platform - business profiles, TrustIndex, star ratings, industry rankings, NPS, response time, contact details and individual consumer reviews.

- **URL**: https://apify.com/ahmed_jasarevic/hellopeter-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.93 / 1,000 reviews

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

## HelloPeter Scraper

Scrape [HelloPeter](https://www.hellopeter.com), **South Africa's largest review platform**, into two datasets: **business profiles** with TrustIndex, star ratings, industry rankings, NPS and response metrics, plus **individual consumer reviews** with text, ratings, verified-purchase flags and business replies.

Built for local-market research, competitor review monitoring, brand reputation tracking, customer-experience analytics and South African market entry.

Two datasets: **BUSINESSES** and **REVIEWS**, linked by `businessSlug`.

### What you get

#### TrustIndex — the metric South African buyers actually shop on

`trustIndex`, `trustIndexText`, `starRating`, `starDistribution`, `totalReviewCount`, `nps`. TrustIndex is HelloPeter's proprietary composite score and it is the number South African consumers use to choose between otherwise similar local businesses. It is **not** recomputable from star rating and review count, so you cannot substitute one for the other.

`starDistribution` gives you the full 5→1 breakdown rather than just the average, and `reviewHistory` carries the score's movement over time — that pair is what turns "this business is well rated" into "this business is improving or declining".

#### Consumer-experience metrics, not just stars

`responseTime`, `negativeReplyTime`, `negativeResponseRate`. These are the operational half of a review platform, and they are the differentiator: how fast a business answers, and — critically — **how fast it answers its negative reviews**. A business with a 3.2 TrustIndex that replies to criticism in 4 hours is operationally very different from one that ignores it for three weeks, and only these fields separate them.

#### Industry leaderboards as a competitive set

`kind: "industryListing"` rows carry `industry`, `industrySlug`, `industryRank`, `subCategory`, `subCategoryRank` and `rankings[]`. Instead of guessing who your competitors are, you walk HelloPeter's own category leaderboard and get a ranked, verified competitive set per industry — including where a business sits in its subcategory.

#### AI-generated business summaries

`aiSummary`, `aiThemes`, `keywords`, `popularMentions`. HelloPeter generates its own AI summary and theme extraction for each profile, and `aiThemes` arrives as structured objects. Useful as a ready-made thematic digest of hundreds of reviews — but read [Legal & Compliance](#legal--compliance) before republishing platform-generated summaries.

#### Full contact blocks from profiles

`contact` (address, phone, email, website), `website`, `logo`. For a local business directory or an outreach list this is the payload, and it comes from the profile page rather than from guesswork.

#### Reviews with the metadata that makes them analysable

`authorName`, `authorId`, `authorMemberSince`, `verifiedPurchase`, `rating`, `title`, `text`, `date`, `dateIso`, `helpfulCount`, `replyCount`, `businessReply`, `businessReplyDate`. `verifiedPurchase` separates genuine customer experience from unattributed noise, `authorMemberSince` helps you discount sockpuppet patterns, and `businessReply` lets you measure whether a business actually responds to complaints.

### How it works

HelloPeter is a JavaScript application, so the Actor runs a **`CheerioCrawler`** that fetches HTML and parses the embedded payload — no JavaScript execution, no headless browser, no captcha solving.

#### Only sitemap-declared and public paths are touched

Every incoming URL is classified before anything is fetched, and disallowed categories are **skipped by design**:

| Path | Treatment |
| --- | --- |
| `/sitemaps/**` | **Allowed** — sitemap discovery, explicitly declared in `robots.txt` |
| `/{business-slug}` | **Allowed** — public business profile page |
| `/{business-slug}/reviews/{id}` | **Allowed** — public review page |
| `/industries/**` | **Allowed** — industry leaderboard pages |
| `/profile/*`, `/sign*`, `/admin*`, `/private*`, `/terms*`, `/about*`, `/search*`, `/` | **Skipped** — never fetched |

That skip list is enforced in code, not just documented. In particular the Actor **never requests the robots-disallowed `/profile/` path** — business data always comes from public root URLs.

#### The one exception you should know about

`searchQueries` is the only input that touches **`/api/search`**, which HelloPeter's `robots.txt` disallows under `/api/`. There are compliant alternatives that do the same job:

- `startUrls` with direct business URLs,
- `businessSlugs` for a known list of businesses,
- `industrySlugs` to enumerate businesses by category,
- `useSitemapDiscovery: true` for bulk discovery from the published sitemap index.

**Prefer those.** Use `searchQueries` only if you accept the extra constraint, and see [Legal & Compliance](#legal--compliance).

#### Where reviews come from

HelloPeter publishes **weekly review sitemaps** under `/sitemaps/reviews/`. One weekly sitemap contains exactly the reviews posted that week. The Actor reads up to `sitemap-index.xml` → filters review sitemaps → scans the **6 most recent**, groups review permalinks by business slug and queues them **newest first**.

So reviews arrive **recency-first**, which is exactly what you want for monitoring — and there is no pagination to walk, because the weekly sitemap already tells you what is new.

Budget note: each extra review sitemap scanned costs one request, and `maxReviewsPerBusiness` (default **28**) caps the *total* per business across profile page plus sitemap.

#### Discovery requests don't consume the crawl budget

Sitemap and search fetches run through a separate lightweight `got-scraping` client rather than the crawler, so `maxRequestsPerCrawl` (default **200**) is spent on **profile and review pages** — the pages that produce data — not on XML.

`truncatedFields` records any field the page shortened server-side, so you can tell "HelloPeter doesn't publish this" apart from "our fetch cut it off".

### Input

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `startUrls` | string\[] | `[]` | Any mix of business, industry, review, sitemap or search URLs. Auto-classified. |
| `searchQueries` | string\[] | `[]` | **Hits `/api/search`, which `robots.txt` disallows.** Compliant alternatives below. |
| `businessSlugs` | string\[] | `[]` | Known business slugs, e.g. `capitec-banking`. Direct profile fetch. |
| `industrySlugs` | string\[] | `[]` | Industry slugs to enumerate as leaderboard pages. |
| `useSitemapDiscovery` | boolean | `false` | Bulk discovery from `/sitemaps/sitemap-index.xml`. **The compliant way to go broad.** |
| `sitemapMaxSitemaps` | integer | `1` | How many business sitemaps to follow per run. |
| `maxBusinesses` | integer | `20` | Cap on business records. |
| `includeReviews` | boolean | `true` | Pull reviews as well as profiles. |
| `maxReviewsPerBusiness` | integer | `28` | Total reviews per business, profile page + sitemap combined. |
| `maxIndustryPages` | integer | `1` | Cap on industry leaderboard pages. |
| `maxRequestsPerCrawl` | integer | `200` | Crawl budget for profile and review pages. |
| `maxConcurrency` | integer | `8` | Parallel requests. |
| `requestHandlerTimeoutSecs` | integer | `60` | Per-request handler timeout. |
| `proxy` | object | — | Standard Apify proxy picker. |

Compliant discovery, instead of `searchQueries`:

```json
{
  "useSitemapDiscovery": true,
  "sitemapMaxSitemaps": 2,
  "maxBusinesses": 100
}
```

Specific businesses:

```json
{
  "businessSlugs": ["capitec-banking", "nedbank"],
  "includeReviews": true,
  "maxReviewsPerBusiness": 50
}
```

An industry competitive set with reviews:

```json
{
  "industrySlugs": ["banks", "insurance"],
  "maxIndustryPages": 2,
  "maxBusinesses": 60,
  "maxReviewsPerBusiness": 30
}
```

### Output

Two datasets, cleanly separated.

#### BUSINESSES — 36 fields

Discriminate on **`kind`**: `business` (full profile), `industryListing` (leaderboard row), `searchResult` (API search hit), `error` (diagnostic row with no work done).

| Group | Fields |
| --- | --- |
| Discriminator | `kind`, `message` |
| Identity | `businessName`, `businessSlug`, `businessId`, `profileUrl`, `website`, `logo` |
| Content | `about`, `aiSummary`, `aiThemes`, `keywords`, `popularMentions`, `faq` |
| Contact | `contact` (address, phone, email, website) |
| Ratings | `trustIndex`, `trustIndexText`, `starRating`, `starDistribution`, `totalReviewCount`, `reviewCountEmbedded`, `reviewCountLast12Months`, `reviewHistory` |
| Service | `nps`, `status`, `responseTime`, `negativeReplyTime`, `negativeResponseRate` |
| Classification | `industry`, `industrySlug`, `industryRank`, `subCategory`, `subCategoryRank`, `rankings` |
| Hygiene | `truncatedFields`, `scrapedAt` |

Views: **Business overview**.

#### REVIEWS — 22 fields

`kind`, `id`, `businessName`, `businessSlug`, `businessUrl`, `industry`, `authorName`, `authorId`, `authorMemberSince`, `verifiedPurchase`, `rating`, `title`, `text`, `date`, `dateIso`, `helpfulCount`, `replyCount`, `businessReply`, `businessReplyDate`, `url`, `source`, `scrapedAt`

Views: **Review overview**, **Review text**.

Field notes that change how you read the data:

- **Join the datasets on `businessSlug`**, not `businessName` — names repeat and change.
- `kind: "error"` rows exist so a failed fetch is visible instead of silently missing. Filter them out before analysis; `message` says why.
- `reviewCountEmbedded` vs `totalReviewCount` are **two sources of the same thing**. The embedded count comes from the profile page; the total may come from a richer path. When they disagree, the profile page's own number is usually the one shown to users.
- `reviewCountLast12Months` isolates recent activity — the field that distinguishes a business with 3,000 lifetime reviews from one actually being reviewed now.
- `businessReply` is deliberately **untyped** (object, string, or null) because its shape varies. Handle all three cases.
- `date` is the human-readable date; **`dateIso` is the one to sort and filter on**.
- `aiSummary`/`aiThemes` are **HelloPeter's own generated content**, not verbatim review data.
- `truncatedFields` lists fields the server shortened — check it before trusting a suspiciously short `about`.

### Example input

Compliant broad discovery:

```json
{
  "useSitemapDiscovery": true,
  "sitemapMaxSitemaps": 2,
  "maxBusinesses": 100,
  "maxRequestsPerCrawl": 400
}
```

Track specific businesses and their latest reviews:

```json
{
  "businessSlugs": ["capitec-banking", "standard-bank", "sasol"],
  "includeReviews": true,
  "maxReviewsPerBusiness": 50,
  "maxRequestsPerCrawl": 300
}
```

Competitive set from an industry leaderboard:

```json
{
  "industrySlugs": ["banks", "airlines"],
  "maxIndustryPages": 3,
  "maxBusinesses": 80,
  "maxReviewsPerBusiness": 25
}
```

Direct URLs, mixed with reviews off:

```json
{
  "startUrls": [
    "https://www.hellopeter.com/capitec-banking",
    "https://www.hellopeter.com/industries/banks"
  ],
  "includeReviews": false,
  "maxBusinesses": 50
}
```

### Example output

```json
{
  "kind": "business",
  "message": null,
  "businessName": "Capitec Business",
  "businessSlug": "capitec-business",
  "businessId": "biz_8f21c4a90",
  "profileUrl": "https://www.hellopeter.com/capitec-business",
  "website": "https://www.capitec.co.za",
  "logo": "https://www.hellopeter.com/assets/logos/capitec-business.png",
  "about": "Capitec Business provides business banking solutions to South African SMEs, including business accounts, credit facilities, vehicle finance and merchant services.",
  "aiSummary": "Reviewers frequently praise fast account opening and helpful relationship managers, with recurring complaints about long hold times on the phone line and proactive fee changes.",
  "aiThemes": [
    { "theme": "Service speed", "sentiment": "positive", "mentions": 184 },
    { "theme": "Fees", "sentiment": "negative", "mentions": 97 }
  ],
  "keywords": ["business banking", "small business", "credit"],
  "popularMentions": ["relationship manager", "account opening", "vehicle finance"],
  "faq": [
    { "question": "Does Capitec Business offer a business account?", "answer": "Yes — a free business account with no monthly fee." }
  ],
  "contact": {
    "address": "15 Simmonds Street, Cape Town, 8001",
    "phone": "021 555 1234",
    "email": "business@capitec.co.za",
    "website": "https://www.capitec.co.za"
  },
  "trustIndex": 4.2,
  "trustIndexText": "Excellent",
  "starRating": 4.2,
  "starDistribution": { "5": 1284, "4": 402, "3": 118, "2": 47, "1": 203 },
  "totalReviewCount": 2054,
  "reviewCountEmbedded": 2054,
  "reviewCountLast12Months": 611,
  "reviewHistory": [
    { "month": "2026-09", "trustIndex": 4.1, "reviewCount": 58 },
    { "month": "2026-10", "trustIndex": 4.2, "reviewCount": 63 }
  ],
  "nps": 62,
  "status": "Claimed",
  "responseTime": "2 hours",
  "negativeReplyTime": "4 hours",
  "negativeResponseRate": 0.94,
  "industry": "Banks",
  "industrySlug": "banks",
  "industryRank": 3,
  "subCategory": "Business Banking",
  "subCategoryRank": 1,
  "rankings": [
    { "name": "Capitec Business", "rank": 1, "trustIndex": 4.2, "reviewCount": 2054 }
  ],
  "truncatedFields": [],
  "scrapedAt": "2026-10-04T06:12:41.220Z"
}
```

### Integrations & automation

Call it over the Apify API (`POST /v2/acts/zBUcP0d6qle75s6Qo/runs`), or from Python, JavaScript, the CLI or MCP. Both datasets export as JSON, CSV, Excel, XML or RSS.

For **reputation monitoring**, schedule a daily run over a fixed `businessSlugs` list, upsert BUSINESSES on `businessSlug`, insert REVIEWS on `id`, and alert when `trustIndex` moves, when `reviewCountLast12Months` drops sharply, or when a new 1- or 2-star `verifiedPurchase` review appears. The **weekly review sitemaps are newest-first**, so a daily run captures new reviews without any pagination walking.

For **South African market entry**, use `industrySlugs` to get a ranked competitive set, then join reviews to compute category-level sentiment norms — so you can tell whether a 4.2 TrustIndex is good *for that industry* or just good in absolute terms. For **customer-experience research**, filter REVIEWS on `verifiedPurchase: true` and analyse `businessReply` against `rating` to measure whether replying to a complaint actually correlates with better subsequent scores.

Typical pipeline: run on schedule → drop `kind: "error"` rows → join on `businessSlug` → upsert businesses → insert reviews → alert on `trustIndex` deltas and new negative `verifiedPurchase` reviews.

#### What a run costs

| Configuration | Billable events | Cost |
| --- | --- | --- |
| 20 businesses, no reviews | 20 × Profile | **$0.02** |
| 20 businesses × 28 reviews | 20 Profile + 560 Review | **$0.55** |
| 100 businesses, no reviews | 100 × Profile | **$0.10** |

Two separate event types: **$0.00095 per business profile** and **$0.00095 per review**. Reviews dominate cost by volume, so `includeReviews: false` or a low `maxReviewsPerBusiness` is the fastest way to cut a bill. Free accounts get a trial quota; paying accounts get full caps and tiered rates.

### Related Actors

| Actor | Why |
| --- | --- |
| [`google-maps-scraper`](https://apify.com/ahmed_jasarevic/google-maps-scraper) | The other major local-reputation source — pair Google ratings with HelloPeter TrustIndex for the same business. |
| [`trustpilot-scraper`](https://apify.com/ahmed_jasarevic/trustpilot-scraper) | International review data, useful for South African businesses trading internationally. |
| [`indeed-scraper`](https://apify.com/ahmed_jasarevic/indeed-scraper) | South African employer reviews alongside job data. |
| [`glassdoor-scraper`](https://apify.com/ahmed_jasarevic/glassdoor-scraper) | Employee-side reputation to complement customer-side review data. |
| [`yellowpages-ca-scraper`](https://apify.com/ahmed_jasarevic/yellowpages-ca-scraper) | Business directory data for enriching a HelloPeter competitive set with contact and category data. |

### FAQ

#### Which input should I use instead of `searchQueries`?

`searchQueries` is the only input that touches `/api/search`, which HelloPeter's `robots.txt` disallows. The compliant alternatives do the same work: `businessSlugs` for a known list, `industrySlugs` to enumerate by category, `useSitemapDiscovery: true` for bulk discovery from the published sitemap index, or `startUrls` with direct business URLs. Prefer those unless you have a specific reason not to.

#### Do I need a browser?

No. The Actor uses `CheerioCrawler`, which fetches HTML and parses the embedded payload without executing JavaScript. No headless browser, no captcha solving.

#### How do I join the two datasets?

On **`businessSlug`**. Do not join on `businessName` — names are not unique and businesses rename. `businessSlug` is stable, and REVIEWS also carries `businessUrl` if you prefer URL-based joins.

#### Why are there rows with `kind: "error"`?

So failures are visible. Rather than silently dropping a fetch that returned nothing usable, the Actor pushes a diagnostic row with `kind: "error"` and a human-readable `message`. Filter them out before analysis — but don't delete them blindly, since a run full of `error` rows usually means a URL problem, not an empty market.

#### Why is `totalReviewCount` different from `reviewCountEmbedded`?

They come from different sources: `reviewCountEmbedded` is read from the profile page payload, while `totalReviewCount` may come from a richer path with additional context. When they disagree, prefer `reviewCountEmbedded` as the number a user would see, and use `totalReviewCount` as the broader figure.

#### How do I get only the newest reviews?

Reviews are queued **newest-first** from the weekly review sitemaps, and `maxReviewsPerBusiness` caps the total. So a daily run with a low `maxReviewsPerBusiness` — say `10` — gives you the 10 most recent reviews per business and nothing older. Keep `id` as your dedupe key across runs.

#### What does `truncatedFields` mean?

It lists fields the server itself shortened when rendering the page. If `about` looks suspiciously short, check this array before assuming a parse bug — the page may simply have truncated it.

#### Can I compare businesses across industries on TrustIndex?

You can, but be careful. TrustIndex is computed against a category-relative baseline in HelloPeter's model, so a 4.2 in banking is not the same achievement as a 4.2 in restaurants. Use `industrySlug` and `industryRank` to normalise before drawing conclusions, rather than comparing raw scores across unrelated categories.

#### Do reviews contain real customer names?

Yes — `authorName` and `authorId` are real individuals, and `authorMemberSince` reveals account age. That makes this personal data with real obligations. Read [Legal & Compliance](#legal--compliance) before you store, analyse or redistribute it.

### SEO Keywords

hellopeter scraper, hellopeter.com, south africa reviews, trustindex, south africa business reviews, local business reputation, sa customer reviews, review monitoring, competitor review analysis, business reputation tracking, star rating data, south africa market research, industry leaderboard, nps data, customer experience analytics, verified purchase reviews, business response time, sa brand reputation, review sentiment analysis, local seo data, south africa business directory, reputation management, review data api

### For AI Agents & LLM Apps

Returns HelloPeter data as **two datasets** — BUSINESSES (36 fields, discriminate on `kind`) and REVIEWS (22 fields) — linked by `businessSlug`.

**Minimal input** — smallest valid run:

```json
{ "businessSlugs": ["capitec-business"] }
```

**Compliant broad discovery** (use this rather than `searchQueries`):

```json
{ "useSitemapDiscovery": true, "sitemapMaxSitemaps": 2, "maxBusinesses": 100 }
```

**Profiles without reviews** (cheapest):

```json
{ "businessSlugs": ["capitec-business", "nedbank"], "includeReviews": false }
```

**Full competitive set with reviews**:

```json
{ "industrySlugs": ["banks"], "maxIndustryPages": 2, "maxBusinesses": 60, "maxReviewsPerBusiness": 30 }
```

**Output fields — BUSINESSES (36):** kind, message, businessName, businessSlug, businessId, profileUrl, website, logo, about, aiSummary, aiThemes, keywords, popularMentions, faq, contact, trustIndex, trustIndexText, starRating, starDistribution, totalReviewCount, reviewCountEmbedded, reviewCountLast12Months, reviewHistory, nps, status, responseTime, negativeReplyTime, negativeResponseRate, industry, industrySlug, industryRank, subCategory, subCategoryRank, rankings, truncatedFields, scrapedAt

**Output fields — REVIEWS (22):** kind, id, businessName, businessSlug, businessUrl, industry, authorName, authorId, authorMemberSince, verifiedPurchase, rating, title, text, date, dateIso, helpfulCount, replyCount, businessReply, businessReplyDate, url, source, scrapedAt

**Behaviours an agent should know**

- **Two datasets.** Run IDs and dataset IDs differ — you must fetch both. Link them on `businessSlug`, never `businessName`.
- **Always filter BUSINESSES on `kind`** (`business`, `industryListing`, `searchResult`, `error`). `error` rows are diagnostics, not data — filter them out or your analysis silently includes failures.
- **`searchQueries` hits a robots-disallowed endpoint.** For broad work use `useSitemapDiscovery`, `businessSlugs`, `industrySlugs` or `startUrls` instead.
- **Two billing event types:** $0.00095 per business profile and $0.00095 per review. Reviews dominate by volume — `includeReviews: false` or a low `maxReviewsPerBusiness` cuts cost fastest.
- Reviews arrive **newest-first** from weekly review sitemaps, and only the 6 most recent weekly sitemaps are scanned. Anything older than ~6 weeks is not discoverable this way; use `businessSlugs` for historical depth.
- `dateIso` is the field to sort and filter on. `date` is display-formatted.
- `businessReply` is **untyped** — it can be an object, a string, or null. Handle all three.
- `totalReviewCount` and `reviewCountEmbedded` are two counts of the same thing from different sources; prefer `reviewCountEmbedded`.
- `aiSummary`, `aiThemes`, `keywords` and `popularMentions` are **HelloPeter's generated content**, not verbatim source data.
- `contact` and `truncatedFields` are objects/arrays respectively — parse defensively.
- The Actor never requests `/profile/`, `/sign`, `/admin` or `/private` paths; those are skipped in code.
- Sitemap fetches bypass the crawl budget, so `maxRequestsPerCrawl` (default 200) is spent on data-producing pages only.
- No browser is used — `CheerioCrawler` only.

### Legal & Compliance

This Actor is an independent third-party tool. It is not affiliated with, endorsed by, or sponsored by HelloPeter, or by any business whose profile or reviews appear in its output.

**What it actually accesses:** public HelloPeter business profile pages at their root URLs, public review pages at `/{slug}/reviews/{id}`, public industry leaderboard pages, and the XML sitemaps that HelloPeter's `robots.txt` explicitly declares. No login, no authentication, no captcha solving, no browser.

**What it deliberately does not touch:** HelloPeter's `robots.txt` disallows `/api/` and `/profile/`. The Actor's URL classifier **skips `/profile`, `/sign`, `/admin`, `/private`, `/terms`, `/about` and `/search` paths by design**, and never requests the disallow-listed `/profile/` path. The **single exception** is the `searchQueries` input, which calls `/api/search`. **Use `businessSlugs`, `industrySlugs`, `useSitemapDiscovery` or `startUrls` instead** — they cover the same use cases on sitemap-declared, permitted paths.

**Personal data — this is the serious part.** The REVIEWS dataset contains **identifiable consumer data**: `authorName`, `authorId`, `authorMemberSince` and review `text`. In South Africa this is governed by the **Protection of Personal Information Act (POPIA)**, with **GDPR** applying to any EU residents' reviews and **CCPA/other state laws** to California residents. Reviews also carry reputational significance, which means a wrong or outdated record can cause real harm to a real person.

If you process this data you are the responsible party and you must: give **notice** to affected individuals, honour **access and erasure requests**, restrict processing to a stated lawful purpose, apply **appropriate security safeguards**, and delete or anonymise once the purpose is met. Do not build profiles of individual reviewers, do not re-identify pseudonymous reviewers, and do not use review text to make automated decisions about people.

**Platform-generated content.** `aiSummary`, `aiThemes`, `keywords` and `popularMentions` are **HelloPeter's own generated output**. Treat them as HelloPeter's intellectual property, not as public-domain facts, and get permission before republishing them.

**Review and profile content ownership.** Review text belongs to its individual authors; business profiles, logos and contact details belong to the businesses. Review aggregation and display may also carry attribution obligations to the individual reviewer. Republishing review text at scale without the author's consent can breach both the authors' rights and HelloPeter's Terms of Use.

**Commercial terms.** HelloPeter's Terms of Use reserve rights over its database, ratings model and generated content. Building a competing review or reputation product from this data is likely to breach them. If you need South African review data commercially, a licence from HelloPeter is the defensible route.

You are solely responsible for compliance with HelloPeter's Terms of Use, `robots.txt`, POPIA, and applicable law. Keep runs modest — the default `maxRequestsPerCrawl: 200` and `maxConcurrency: 8` bound a run without effort — and prefer the sitemap and slug-based inputs over `searchQueries`.

# Actor input Schema

## `startUrls` (type: `array`):

Direct hellopeter.com URLs to scrape. Business profile pages look like https://www.hellopeter.com/dis-chem , industry ranking pages like https://www.hellopeter.com/industries/retail , and individual review pages like https://www.hellopeter.com/mtn/reviews/<slug>-<uuid> . Discovery URLs (sitemap index, /api/search) are also accepted.

## `searchQueries` (type: `array`):

Look up businesses by name through the public https://www.hellopeter.com/api/search?q= JSON endpoint, then scrape each matching profile. Example: \["dis-chem", "capitec", " Vodacom"].

## `businessSlugs` (type: `array`):

Business slugs to scrape directly, e.g. \["dis-chem", "mtn", "capitec-business"]. Equivalent to visiting https://www.hellopeter.com/<slug> .

## `industrySlugs` (type: `array`):

Industry pages to scrape for industry ranking leaderboards. Available slugs: https://www.hellopeter.com/industries/<slug> . One row per ranked business is produced.

## `useSitemapDiscovery` (type: `boolean`):

When true, reads https://www.hellopeter.com/sitemaps/sitemap-index.xml and pulls business profile URLs from the business sitemaps. Combine with maxBusinesses to stay inside a sane budget.

## `sitemapMaxSitemaps` (type: `integer`):

How many business sitemaps to read when sitemap discovery is enabled. Each sitemap holds 1,000 business URLs.

## `maxBusinesses` (type: `integer`):

Maximum number of business profile pages to scrape. Hard cap for safety.

## `includeReviews` (type: `boolean`):

Collect consumer reviews into the REVIEWS dataset. Switch on: the reviews server-rendered on each business profile are saved, and the newest weekly review sitemap is matched against the businesses in this run to pull their most recent reviews too - automatically, no extra setup. Switch off: only the BUSINESSES dataset is produced and no review pages are fetched.

## `maxReviewsPerBusiness` (type: `integer`):

Total number of reviews to collect for each business: the reviews HelloPeter server-renders on the profile page, plus extra reviews fetched from the newest weekly review sitemap. Every extra review costs one additional request. Set to 0 to collect businesses only, or to 8 to keep just the free profile-page reviews. Only used when includeReviews is true.

## `maxIndustryPages` (type: `integer`):

How many pages of the industry ranking leaderboard to follow. Each page lists 20 ranked businesses.

## `maxRequestsPerCrawl` (type: `integer`):

Safety cap on the total number of HTTP requests for the whole run.

## `maxConcurrency` (type: `integer`):

How many pages to fetch in parallel. Keep this modest.

## `requestHandlerTimeoutSecs` (type: `integer`):

Per-request timeout.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "useSitemapDiscovery": false,
  "sitemapMaxSitemaps": 1,
  "maxBusinesses": 20,
  "includeReviews": true,
  "maxReviewsPerBusiness": 28,
  "maxIndustryPages": 1,
  "maxRequestsPerCrawl": 200,
  "maxConcurrency": 8,
  "requestHandlerTimeoutSecs": 60,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `businesses` (type: `string`):

One row per business: business profile, industry leaderboard entry or search hit. Fields: businessName, businessSlug, profileUrl, trustIndex, starRating, totalReviewCount, nps, industry, industryRank, contact, aiSummary, aiThemes, rankings, faq.

## `reviews` (type: `string`):

One row per consumer review, linked to its business by businessSlug. Fields: businessName, businessSlug, authorName, rating, title, text, date, dateIso, helpfulCount, verifiedPurchase, businessReply, url.

# 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 = {
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/hellopeter-scraper").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 = { "proxy": { "useApifyProxy": False } }

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/hellopeter-scraper").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 '{
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/hellopeter-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/hellopeter-scraper"
        }
    }
}
```

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/zBUcP0d6qle75s6Qo/builds/SSncNEXu0L1EZI4zF/openapi.json
