# Otto Email Scraper (`leads-scraper/otto-email-scraper`) Actor

Otto Email Scraper SD - Otto Email Scraper is a lead generation tool that extracts leads with public contact emails, account names and profile URLs from Otto results by keyword, location and email domain - Otto email extractor.

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

## Pricing

from $2.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

### Otto Email Scraper

The Otto Email Scraper collects publicly indexed contact emails connected to `otto.de`, one of Germany's largest online retailers.
It builds Google queries with the `site:otto.de` operator, fetches them through the Apify GOOGLE\_SERP proxy, and extracts emails from the result blocks.
No login, no browser, no OTTO API — only what Google has already published in its index.

**Start with the honest part.** OTTO is a first-party retailer with mostly German-language pages, so results are brand pages rather than seller profiles.
Set `countryCode` to `DE` and use German keywords. Both of those are conditions for the Otto Email Scraper working at all, not optional refinements.

That distinction shapes everything else in this document.
What the Otto Email Scraper realistically surfaces is supplier, brand and press contact details published on OTTO's own pages — not the inboxes of independent marketplace sellers.
If you need third-party marketplace sellers with handles and profile URLs, the [Cdiscount Email Scraper](https://apify.com/neuro-scraper/cdiscount-email-scraper) and the [Allegro Email Scraper](https://apify.com/neuro-scraper/allegro-email-scraper) are structurally better suited to that job.

#### What one run of the Otto Email Scraper produces

Each dataset row is one unique email plus whatever account context Google printed around it.
You get the raw title, an account label, a snippet, the exact query used and a truncation flag.
The Otto Email Scraper pushes rows to the Apify dataset as they are found, so you can export CSV or JSON mid-run.

### Why the Otto Email Scraper uses German keywords by default

`otto.de` is indexed almost entirely in German. Query language is the main lever you have here, and it is not a small one.
An English query such as `seller contact` will match essentially nothing on `otto.de`.

The default `keywords` are `haendler` (retailer/dealer) and `marke` (brand).
The default `queryModifiers` are `email`, `kontakt`, `grosshandel` (wholesale), `kundenservice` (customer service) and `vertrieb` (sales/distribution).

These defaults are deliberate. Note the ASCII transliterations — `haendler` rather than `händler`, `grosshandel` rather than `großhandel`.
Google treats the umlaut and its `ae`/`ss` transliteration as broadly equivalent, and ASCII forms travel more reliably through query building. Add the umlaut spellings as extra keywords if you want to test both.

#### Setting `countryCode` for the Otto Email Scraper

Set `countryCode` to `DE`. This is called out explicitly in the Otto Email Scraper's own input description for a reason.
The Apify GOOGLE\_SERP proxy then searches from a German vantage point, and Google's country personalisation surfaces `otto.de` pages that a default or US-country search will not rank at all.

Running the Otto Email Scraper with an empty `countryCode` and English keywords is the fastest way to get an empty dataset.
`countryCode: "DE"` plus German keywords is the configuration the Otto Email Scraper expects.

#### German free-mail domains for `customDomains`

The default `customDomains` are `@gmail.com` and `@yahoo.com`.
Keep Gmail. Yahoo is comparatively rare in Germany and is usually worth replacing.

These German providers are worth testing. They are suggestions based on how the German market publishes contact details, not guarantees of volume:

| Domain | Why add it for OTTO |
|---|---|
| `@web.de` | One of the two dominant German free-mail providers |
| `@gmx.de` | The other dominant German provider, very common with SMEs |
| `@gmx.net` | The `.net` variant of the same service |
| `@t-online.de` | Telekom mail, long-established with older German businesses |
| `@gmail.com` | Keep — still widely used overall |

Every additional domain multiplies the query count, because the Otto Email Scraper searches each keyword against each domain.
Given the low expected yield on this platform, prefer a small, well-chosen domain set over a wide sweep.

#### German keyword ideas beyond the defaults

Try `lieferant` (supplier), `grosshaendler` (wholesaler), `hersteller` (manufacturer), `partner`, `unternehmen` and `presse` (press).
Add a vertical: `moebel`, `elektronik`, `mode`, `haushalt`, `garten`.
Because OTTO publishes brand and supplier pages, `lieferant` and `marke` variants tend to be more productive than seller-flavoured terms.

### Otto Email Scraper features

Everything listed below is implemented in the Otto Email Scraper today.

| Feature | What it means in practice |
|---|---|
| German-first defaults | `keywords` and `queryModifiers` are tuned for `otto.de`, not translated from English |
| Query expansion | Base, quoted, `intitle:` and one variant per modifier; base queries run first |
| Global deduplication | An email found by several queries is stored exactly once |
| Email normalisation | Understands `name [at] domain [dot] de`, `name (at) domain`, `name @ domain`, `domain .com`, zero-width characters and the full-width `＠` |
| Junk filter | Rejects placeholders such as `email@`, `yourname@`, `test@`, `xxx@` and single-character locals |
| Boundary-correct matching | `@gmail.com` will not match inside `@gmail.company` or `@gmail.com.br` |
| Soft-wrap repair | Drops a hit that is only the tail of another email in the same block |
| Structural parsing | Finds the `<h3>` and the smallest surrounding block, so it does not depend on Google's CSS class names |
| Whole-page fallback | If Google's markup changes, the run degrades to "emails without account details" rather than "no emails" |
| Block detection | CAPTCHA, "unusual traffic" and consent pages are detected and retried, not counted as empty |
| Retries | Up to 3 attempts per page with exponential backoff and a fresh proxy session per request |
| Failed-query requeue | Blocked or failed queries are re-queued once at the end of the run |
| Concurrency | An `asyncio` worker pool with a shared stop signal on `maxEmails` |
| Resumable state | Key-value store state keyed by an input hash; saves on `PERSIST_STATE`, `MIGRATING` and `ABORTING` |
| Run summary | Logs pages fetched, blocked pages, retries and emails per page |

### How the Otto Email Scraper works

The Otto Email Scraper runs the same six steps on every query it builds.

1. It reads your input: keywords, location, email domains and limits.
2. It builds Google queries with the `site:` operator against `otto.de`, for example `site:otto.de marke "@web.de" kontakt`.
3. It fetches result pages through the Apify GOOGLE\_SERP proxy using async `aiohttp` requests.
4. It parses each result block structurally rather than by CSS class name.
5. It extracts emails with a domain-filtered regex and normalises obfuscated forms.
6. It deduplicates globally and pushes each lead to the dataset immediately.

There is no browser, no JavaScript rendering, no authentication and no cookies.
The Otto Email Scraper never signs into OTTO and never requests pages from OTTO's own servers.
Everything it returns was already public in Google's search index.

### Otto Email Scraper input fields

These are the exact input fields the Otto Email Scraper accepts, with the defaults it ships with.

| Field | Type | Default | Meaning |
|---|---|---|---|
| `keywords` | array (required) | `["haendler","marke"]` | Search terms describing the accounts you want |
| `location` | string | `""` | Optional location phrase added to every query |
| `customDomains` | array | `["@gmail.com","@yahoo.com"]` | Only emails on these domains are kept; `@` optional |
| `maxEmails` | integer 1-10000 | `20` | Stop after this many unique emails |
| `countryCode` | string | `""` | Two-letter country for the search proxy — set `DE` here |
| `expandQueries` | boolean | `true` | Search each keyword x domain in several phrasings |
| `queryModifiers` | array | `["email","kontakt","grosshandel","kundenservice","vertrieb"]` | Extra words combined with each keyword when expansion is on |
| `maxPagesPerQuery` | integer 1-50 | `30` | Page cap per query |
| `maxConcurrency` | integer 1-20 | `5` | Parallel queries |

#### Example Otto Email Scraper input

```json
{
  "keywords": ["haendler", "marke", "lieferant"],
  "location": "Hamburg",
  "customDomains": ["@web.de", "@gmx.de", "@gmail.com"],
  "maxEmails": 100,
  "countryCode": "DE",
  "expandQueries": true,
  "queryModifiers": ["email", "kontakt", "grosshandel", "kundenservice", "vertrieb"],
  "maxPagesPerQuery": 30,
  "maxConcurrency": 5
}
```

The `location` field appends a phrase to every query.
German city names work here — `Hamburg`, `Berlin`, `Muenchen`, `Koeln`, `Frankfurt`.
On a low-yield platform like this one, location filtering narrows an already narrow result set, so use it sparingly.

### Otto Email Scraper output fields

Every dataset item the Otto Email Scraper writes carries all fourteen of these fields.

| Field | Meaning |
|---|---|
| `network` | Platform name |
| `keyword` | The keyword that produced the lead |
| `query` | The exact Google query used |
| `title` | Raw result title |
| `accountName` | Account label Google prints |
| `fullName` | Display name parsed from a profile-style title; empty for post captions |
| `username` | URL-safe handle when the platform exposes one; otherwise `null` |
| `profileUrl` | Canonical account URL when a handle is known; otherwise empty |
| `url` | Direct platform link when exposed, else the profile URL |
| `description` | Bio or snippet text, cleaned of labels and engagement counters |
| `email` | Lower-cased email address |
| `emailDomain` | The matched domain |
| `possiblyTruncated` | `true` when Google's snippet ellipsis touched the email |
| `foundAt` | ISO 8601 UTC timestamp |

#### Example Otto Email Scraper output

```json
[
  {
    "network": "Otto",
    "keyword": "marke",
    "query": "site:otto.de marke \"@web.de\" kontakt",
    "title": "NordWohnen - Marken bei OTTO",
    "accountName": "NordWohnen",
    "fullName": "NordWohnen",
    "username": "nordwohnen",
    "profileUrl": "https://www.otto.de/marken/nordwohnen",
    "url": "https://www.otto.de/marken/nordwohnen",
    "description": "Moebelmarke aus Norddeutschland. Kontakt: vertrieb.nordwohnen@web.de",
    "email": "vertrieb.nordwohnen@web.de",
    "emailDomain": "@web.de",
    "possiblyTruncated": false,
    "foundAt": "2026-08-31T11:20:07Z"
  },
  {
    "network": "Otto",
    "keyword": "lieferant",
    "query": "site:otto.de lieferant \"@gmx.de\" grosshandel",
    "title": "Grosshandel und Lieferanteninformationen - OTTO",
    "accountName": "OTTO Lieferanteninfo",
    "fullName": "",
    "username": null,
    "profileUrl": "",
    "url": "",
    "description": "Anfragen fuer Lieferanten: einkauf.beispielmarke@gmx.de",
    "email": "einkauf.beispielmarke@gmx.de",
    "emailDomain": "@gmx.de",
    "possiblyTruncated": true,
    "foundAt": "2026-08-31T11:21:33Z"
  }
]
```

The second row is the more typical shape on this platform.
`username` is `null` and `profileUrl` is empty because Google printed an informational page title rather than a brand handle, so no `https://www.otto.de/marken/...` URL can be built.
The email and the account label are still usable.

#### What a measured Otto Email Scraper run looked like

A live test run against `otto.de` returned **only 1 result block**.
That is not a defect in the parser; it is what OTTO's first-party structure and German-language indexing produce.

Treat the Otto Email Scraper as a supplementary source, not a primary lead engine.
It is genuinely useful for filling gaps in a German brand-and-supplier list. It is not the Otto Email Scraper to point at if you need hundreds of contacts quickly.

### Use cases for the Otto Email Scraper

Here is where the Otto Email Scraper fits into real prospecting and research workflows.

| Use case | How to configure it |
|---|---|
| German brand contact discovery | `keywords: ["marke","hersteller"]`, `countryCode: "DE"`, `customDomains: ["@web.de","@gmx.de"]` |
| Supplier and wholesale research | Lean on the `grosshandel` and `vertrieb` modifiers |
| Filling gaps in an existing DE list | Match `accountName` against brands you already track and add missing emails |
| Press and partnerships outreach | Add `presse` and `partner` as keywords |
| Market research | Analyse the `query` and `keyword` fields to see which German phrasings surface contact details |
| Competitive brand mapping | Collect which brands OTTO surfaces publicly, alongside any contact data |
| Cross-market enrichment | Run alongside the Zalando and Allegro Actors to build a wider European picture |
| Data-quality benchmarking | Compare the yield here with a true marketplace to calibrate expectations |

### Practical Otto Email Scraper recipes

**Minimum viable run.** German defaults, `countryCode: "DE"`, `maxEmails: 50`.
This is the honest baseline. If it returns little, that is information about the platform, not a misconfiguration.

**Umlaut A/B test.** Run `haendler`/`grosshandel` once, then `händler`/`großhandel` once, and compare.
Google usually treats these as equivalent, but it costs one small run to confirm for your keywords.

**Supplier angle.** Drop seller-flavoured terms entirely and use `lieferant`, `hersteller` and `marke`.
This matches how OTTO's own pages are actually written and tends to be the more productive framing.

**Widen before you deepen.** On a low-yield platform, more keywords beats more pages.
Raise `maxPagesPerQuery` last; add German keyword variants first.

### Responsible use and GDPR

Germany applies the GDPR alongside the BDSG and the UWG, which is strict about unsolicited commercial email.
An address that identifies a natural person is personal data even when it was published on a public web page.

Public availability is not consent. Establish a lawful basis before your first message.
German rules on unsolicited B2B email are notably tighter than in several other EU markets, so do not assume legitimate interest covers you automatically.

Practical steps that keep an Otto Email Scraper workflow defensible:

- Strongly prefer role addresses (`kontakt@`, `vertrieb@`, `presse@`) over addresses naming an individual.
- Keep provenance for every lead — the `query`, `url` and `foundAt` fields exist for exactly this.
- Include a clear sender identity, a stated purpose and a working opt-out in every message.
- Honour opt-outs immediately and check suppression lists before every follow-up.
- Delete data you are not actively using instead of warehousing scraped lists.
- Take German legal advice specifically on the UWG before running cold email at scale.

This is operational guidance, not legal advice.

### Related Actors

The Otto Email Scraper is part of an E-commerce and Marketplaces family sharing this engine.
For a German picture, run it beside the [Zalando Email Scraper](https://apify.com/leads-scraper/zalando-email-scraper) — also a first-party retailer, with the same brand-page caveat.
For genuine third-party marketplace sellers in Europe, the [Allegro Email Scraper](https://apify.com/neuro-scraper/allegro-email-scraper) and [Cdiscount Email Scraper](https://apify.com/neuro-scraper/cdiscount-email-scraper) are more productive, and German independent shops are often reachable through the [Shopify Store Email Scraper](https://apify.com/leads-scraper/shopify-store-email-scraper).

| Actor | What it collects |
|---|---|
| [Otto Email and Phone Number Scraper](https://apify.com/neuro-scraper/otto-email-and-phone-number-scraper) | Emails and phone numbers from Otto |
| [Otto Phone Number Scraper](https://apify.com/neuro-scraper/otto-phone-number-scraper) | Public phone numbers from Otto |
| [AliExpress Email Scraper](https://apify.com/neuro-scraper/aliexpress-email-scraper) | Public contact emails from AliExpress |
| [Allegro Email Scraper](https://apify.com/neuro-scraper/allegro-email-scraper) | Public contact emails from Allegro |
| [Amazon Email Scraper](https://apify.com/leads-scraper/amazon-email-scraper) | Public contact emails from Amazon |
| [Best Buy Seller Email Scraper](https://apify.com/leads-scraper/best-buy-seller-email-scraper) | Public contact emails from Best Buy |
| [BigCommerce Store Email Scraper](https://apify.com/neuro-scraper/bigcommerce-store-email-scraper) | Public contact emails from BigCommerce Store |
| [Cdiscount Email Scraper](https://apify.com/neuro-scraper/cdiscount-email-scraper) | Public contact emails from Cdiscount |
| [Coupang Email Scraper](https://apify.com/neuro-scraper/coupang-email-scraper) | Public contact emails from Coupang |
| [Depop Email Scraper](https://apify.com/leads-scraper/depop-email-scraper) | Public contact emails from Depop |
| [DHgate Email Scraper](https://apify.com/neuro-scraper/dhgate-email-scraper) | Public contact emails from DHgate |
| [eBay Email Scraper](https://apify.com/leads-scraper/ebay-email-scraper) | Public contact emails from eBay |
| [Ecwid Store Email Scraper](https://apify.com/neuro-scraper/ecwid-store-email-scraper) | Public contact emails from Ecwid Store |
| [Etsy Email Scraper](https://apify.com/leads-scraper/etsy-email-scraper) | Public contact emails from Etsy |
| [Faire Email Scraper](https://apify.com/leads-scraper/faire-email-scraper) | Public contact emails from Faire |
| [Flipkart Email Scraper](https://apify.com/leads-scraper/flipkart-email-scraper) | Public contact emails from Flipkart |
| [Home Depot Seller Email Scraper](https://apify.com/leads-scraper/home-depot-seller-email-scraper) | Public contact emails from Home Depot |
| [JD.com Email Scraper](https://apify.com/leads-scraper/jd-com-email-scraper) | Public contact emails from JD.com |
| [Lazada Email Scraper](https://apify.com/neuro-scraper/lazada-email-scraper) | Public contact emails from Lazada |
| [Lowe's Seller Email Scraper](https://apify.com/leads-scraper/lowes-seller-email-scraper) | Public contact emails from Lowe's |
| [MercadoLibre Email Scraper](https://apify.com/neuro-scraper/mercadolibre-email-scraper) | Public contact emails from MercadoLibre |
| [Mercari Email Scraper](https://apify.com/neuro-scraper/mercari-email-scraper) | Public contact emails from Mercari |
| [Newegg Email Scraper](https://apify.com/leads-scraper/newegg-email-scraper) | Public contact emails from Newegg |
| [Overstock Email Scraper](https://apify.com/leads-scraper/overstock-email-scraper) | Public contact emails from Overstock |
| [Poshmark Email Scraper](https://apify.com/leads-scraper/poshmark-email-scraper) | Public contact emails from Poshmark |
| [Rakuten Email Scraper](https://apify.com/neuro-scraper/rakuten-email-scraper) | Public contact emails from Rakuten |
| [Shopee Email Scraper](https://apify.com/leads-scraper/shopee-email-scraper) | Public contact emails from Shopee |
| [Shopify Store Email Scraper](https://apify.com/leads-scraper/shopify-store-email-scraper) | Public contact emails from Shopify Store |
| [Taobao Email Scraper](https://apify.com/leads-scraper/taobao-email-scraper) | Public contact emails from Taobao |
| [Target Seller Email Scraper](https://apify.com/neuro-scraper/target-seller-email-scraper) | Public contact emails from Target |
| [Temu Email Scraper](https://apify.com/leads-scraper/temu-email-scraper) | Public contact emails from Temu |
| [Tmall Email Scraper](https://apify.com/leads-scraper/tmall-email-scraper) | Public contact emails from Tmall |
| [Vinted Email Scraper](https://apify.com/leads-scraper/vinted-email-scraper) | Public contact emails from Vinted |
| [Walmart Email Scraper](https://apify.com/leads-scraper/walmart-email-scraper) | Public contact emails from Walmart |
| [Wayfair Email Scraper](https://apify.com/neuro-scraper/wayfair-email-scraper) | Public contact emails from Wayfair |
| [Wish Email Scraper](https://apify.com/leads-scraper/wish-email-scraper) | Public contact emails from Wish |
| [Wix Stores Email Scraper](https://apify.com/leads-scraper/wix-stores-email-scraper) | Public contact emails from Wix Stores |
| [WooCommerce Email Scraper](https://apify.com/neuro-scraper/woocommerce-email-scraper) | Public contact emails from WooCommerce |
| [Zalando Email Scraper](https://apify.com/leads-scraper/zalando-email-scraper) | Public contact emails from Zalando |
| [AliExpress Email and Phone Number Scraper](https://apify.com/neuro-scraper/aliexpress-email-and-phone-number-scraper) | Emails and phone numbers from AliExpress |
| [Allegro Email and Phone Number Scraper](https://apify.com/neuro-scraper/allegro-email-and-phone-number-scraper) | Emails and phone numbers from Allegro |
| [Amazon Email and Phone Number Scraper](https://apify.com/leads-scraper/amazon-email-and-phone-number-scraper) | Emails and phone numbers from Amazon |

### Otto Email Scraper limitations

Read these before planning anything around the output.

- **OTTO is a first-party retailer with mostly German-language pages, so results are brand pages rather than seller profiles.** Set `countryCode` to DE and use German keywords. This is the defining limitation of the Otto Email Scraper.
- **Very low measured yield.** A live test run returned only 1 result block. Expect a supplementary trickle, not a lead firehose.
- **Publicly indexed emails only.** The Otto Email Scraper finds addresses already visible in Google's index. Nothing behind a login or an internal contact form is reachable.
- **Google's ~300-result cap.** A single query returns roughly 300 results at most, which is why `expandQueries` defaults to `true`.
- **`possiblyTruncated`.** When `true`, Google's snippet ellipsis touched the email and it may be cut off. Verify before sending.
- **`username` and `profileUrl` are frequently empty.** Google often prints a page title with no brand handle, so no canonical `https://www.otto.de/marken/...` URL can be built. That is a Google limitation, not a bug.
- **Apify GOOGLE\_SERP proxy required.** The Otto Email Scraper cannot run without Apify proxy credentials.
- **Free-plan cap.** Free Apify plans stop at 100 emails per run. Paid plans are uncapped.
- **No guaranteed volume.** Results vary with keywords, domains, location and Google's index on the day.
- **Not affiliated with OTTO.** This is an independent tool, not supported, endorsed by or connected to OTTO.

### Otto Email Scraper FAQ

Common questions about the Otto Email Scraper, its inputs and its output.

#### How many results should I expect from the Otto Email Scraper?

Very few. A live test run returned only 1 result block. OTTO is a first-party retailer with mostly German-language pages, so results are brand pages rather than seller profiles, and the pool of indexed pages carrying public emails is small. Plan for a supplementary source.

#### Why is the yield so much lower than on Allegro or Cdiscount?

Those are genuine third-party marketplaces with thousands of indexed seller pages. OTTO sells largely its own stock, so there are far fewer independent seller pages for Google to index.

#### Does the Otto Email Scraper log into OTTO?

No. It never logs in, never calls an OTTO API and never opens otto.de in a browser. It reads Google results through the Apify GOOGLE\_SERP proxy.

#### What should I set `countryCode` to?

`DE`. This is explicitly recommended in the Otto Email Scraper's input description. Without it, Google is unlikely to rank `otto.de` pages highly enough for the Otto Email Scraper to reach them.

#### Why are the default keywords German, and why without umlauts?

`otto.de` is indexed in German, so German terms are required. The ASCII forms `haendler` and `grosshandel` are used because Google treats them as broadly equivalent to the umlaut spellings and they travel more reliably through query building. Test both if you want.

#### Which email domains work best for OTTO?

Start with `@web.de`, `@gmx.de` and `@gmail.com`. `@gmx.net` and `@t-online.de` are worth testing. These are suggestions based on German market habits, not guarantees.

#### Whose emails am I actually finding?

Mostly supplier, brand and press contacts published on OTTO's own pages — not marketplace-seller inboxes. Set expectations accordingly.

#### Why is `username` empty on so many rows?

Google frequently prints an informational or category title rather than a brand handle. Without a handle there is no canonical profile URL to build. `accountName` and `email` are still populated.

#### Does the Otto Email Scraper verify deliverability?

No. It extracts and normalises what Google indexed. Check rows flagged `possiblyTruncated` before using them.

#### Can I resume an interrupted run?

Yes. State lives in the key-value store keyed by a hash of your input, with saves on Apify's `PERSIST_STATE`, `MIGRATING` and `ABORTING` events.

#### What happens when Google blocks a request?

Block, CAPTCHA and consent pages are detected rather than treated as empty. Pages get up to three attempts with exponential backoff, and failed queries are re-queued once at the end of the run.

#### Is scraping OTTO contact emails legal?

The Otto Email Scraper only reads publicly indexed Google results. Whether you may contact those addresses is a separate GDPR and UWG question — see the responsible use section and take your own legal advice.

### Leave a review

If the Otto Email Scraper saved you time, please leave a star rating and a short review on the
Actor page.

Reviews are how other buyers judge whether a tool works, and they tell us which features to
build next.

If something did not work, email <neurodata.apify@gmail.com>
instead - bugs get fixed faster than they get complained about.

### Support

Questions, a bug, or you need a custom build of the Otto Email Scraper? Contact **<neurodata.apify@gmail.com>**.

# Actor input Schema

## `keywords` (type: `array`):

Search terms describing the Otto accounts you want (niche, job title, industry).

## `location` (type: `string`):

Optional location phrase added to every query (e.g. "New York").

## `customDomains` (type: `array`):

Only emails ending with one of these domains are collected. With or without the leading @. Each domain is searched separately, so more domains means more results but a longer run - remove some for a faster, narrower search, or add your own (e.g. @company.com).

## `maxEmails` (type: `integer`):

Stop once this many unique emails have been collected.

## `countryCode` (type: `string`):

Two-letter country code for the search proxy (e.g. US, GB, DE). Empty for any.

## `expandQueries` (type: `boolean`):

Search each keyword x domain pair with several phrasings. Recommended - Google caps a single query at ~300 results.

## `queryModifiers` (type: `array`):

Extra words combined with each keyword when Expand queries is on. Tuned for Otto.

## `maxPagesPerQuery` (type: `integer`):

Google rarely returns more than ~30 pages for one query.

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

How many queries run in parallel.

## Actor input object example

```json
{
  "keywords": [
    "haendler",
    "marke"
  ],
  "location": "",
  "customDomains": [
    "@gmail.com",
    "@yahoo.com"
  ],
  "maxEmails": 20,
  "countryCode": "",
  "expandQueries": true,
  "queryModifiers": [
    "email",
    "kontakt",
    "grosshandel",
    "kundenservice",
    "vertrieb"
  ],
  "maxPagesPerQuery": 30,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `results` (type: `string`):

Records produced by Otto Email Scraper, stored in the run's default dataset.

# 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 = {
    "keywords": [
        "haendler",
        "marke"
    ],
    "location": "",
    "customDomains": [
        "@gmail.com",
        "@yahoo.com"
    ],
    "countryCode": "",
    "queryModifiers": [
        "email",
        "kontakt",
        "grosshandel",
        "kundenservice",
        "vertrieb"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("leads-scraper/otto-email-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 = {
    "keywords": [
        "haendler",
        "marke",
    ],
    "location": "",
    "customDomains": [
        "@gmail.com",
        "@yahoo.com",
    ],
    "countryCode": "",
    "queryModifiers": [
        "email",
        "kontakt",
        "grosshandel",
        "kundenservice",
        "vertrieb",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("leads-scraper/otto-email-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 '{
  "keywords": [
    "haendler",
    "marke"
  ],
  "location": "",
  "customDomains": [
    "@gmail.com",
    "@yahoo.com"
  ],
  "countryCode": "",
  "queryModifiers": [
    "email",
    "kontakt",
    "grosshandel",
    "kundenservice",
    "vertrieb"
  ]
}' |
apify call leads-scraper/otto-email-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leads-scraper/otto-email-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/ziChIvqSGpb61yJLF/builds/cOPgZToOxxFtU4AwL/openapi.json
