# Hitta.se Scraper — Swedish Business Directory Leads (Företag) (`worktech/hitta-scraper`) Actor

Scrape Swedish business leads from hitta.se: company name, phone, email, website, address, postal code, city and county. Search by keyword and city (rörmokare Stockholm) and export B2B leads to JSON, CSV or Excel. Business listings only — no private persons. Pay per result — $2.50 per 1,000 records.

- **URL**: https://apify.com/worktech/hitta-scraper.md
- **Developed by:** [Per Schondell](https://apify.com/worktech) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.50 / 1,000 business records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Hitta.se Scraper — Swedish Business Directory Leads (Företag)

The **hitta.se scraper** that turns Sweden's largest search directory into a clean B2B lead list: company name, **phone number, email, website, street address, postal code, city, county and coordinates** for any trade in any Swedish town. Type `rörmokare` + `Stockholm`, press Start, export **Swedish business leads** to JSON, CSV or Excel.

**Business listings only.** hitta.se also indexes private persons ("personer"). This actor scrapes the company tab (`företag`) exclusively — private-person records cannot be produced, and there is no setting that turns them on. See [Business-only by design](#business-only-by-design).

### What can you do with it?

- **Hitta företag med telefonnummer** — every record carries the phone hitta.se publishes, in international `+46` format, ready for a dialer or CRM
- **Get Swedish business leads with email addresses** — email comes straight out of the search results, no per-company detail crawl and no extra proxy cost. Coverage depends on the market: in city searches 19–24 of every 25 companies had a published email, in a small town like Kiruna only 3 of 11
- **Export hitta.se search results to CSV or Excel** — one clean row per company, stable columns, ready to import
- **Build B2B prospect lists by trade and city** — `elektriker` in Göteborg, `redovisningsbyrå` in Malmö, `snickare` nationwide
- **Skrapa hitta.se företagsuppgifter** — namn, telefon, e-post, hemsida, adress, postnummer, ort och län
- **Feed AI agents and pipelines** — structured JSON via API, webhooks or the Apify MCP server, so an agent can call this scraper as a tool

### Pricing

**$2.50 per 1,000 business records** ($0.0025 per record). You pay only for records actually delivered to your dataset — a failed or empty search costs nothing, because data is pushed to the dataset *before* it is charged.

| Scenario | Records | Run cost |
|----------|---------|----------|
| Plumbers in Stockholm | ~210 | ~$0.53 |
| One trade across the 20 largest Swedish cities | ~3,000 | ~$7.50 |
| Nationwide trade sweep | ~10,000 | ~$25 |

There is **no enriched tier and no per-company detail crawl**: email and website are already in the search results, so everything is delivered at the single per-record price. Compute is a fraction of a browser-based scraper's — this actor runs on plain HTTP, no headless browser.

**No proxy required.** The default configuration uses no proxy at all, so the only platform cost on top of the per-record price is a few cents of compute: measured at roughly **$0.007 per 1,000 records**. If you choose to route through residential proxies, budget about **$0.021 per 1,000 records** instead.

### How to scrape hitta.se (step by step)

1. Click **Try for free** — you need a free Apify account.
2. Enter one or more **Search terms** in Swedish (e.g. `rörmokare`, `elektriker`).
3. Enter **Locations** (e.g. `Stockholm`, `Kiruna`) — or leave empty to search all of Sweden.
4. Optionally adjust **Max results per search** (default 100 per term × location) and the request delay. Leave **Proxy configuration** off — it is not needed.
5. Click **Start**, then open the **Dataset** tab and export as JSON, CSV, Excel, HTML or XML.

Prefer pasting URLs? Put hitta.se **company** search URLs straight into **Start URLs** instead of search terms.

#### Input example

```json
{
  "searchTerms": ["rörmokare", "elektriker"],
  "locations": ["Stockholm", "Uppsala"],
  "maxResultsPerSearch": 200,
  "requestDelayMs": 1000
}
```

#### Output example (one dataset record)

```json
{
  "name": "Örebro Vvs AB",
  "phone": "+4619306969",
  "phones": ["+4619306969", "+46730000100"],
  "email": "info@orebrovvs.se",
  "website": null,
  "street": "Gamla vägen",
  "streetNumber": "10",
  "address": "Gamla vägen 10 A",
  "postalCode": "70227",
  "city": "Örebro",
  "district": "Adolfsberg",
  "county": "Örebro län",
  "latitude": 59.25826725425936,
  "longitude": 15.186285637833427,
  "categories": ["Hus & Hem", "Bygg & Byggmaterial"],
  "reviewScore": null,
  "reviewCount": null,
  "hittaUrl": "https://www.hitta.se/verksamhet/orebro-vvs-ab-kcccsxxyz",
  "sourceUrl": "https://www.hitta.se/s%C3%B6k?vad=r%C3%B6rmokare&typ=ftg&sida=1",
  "searchTerm": "rörmokare",
  "location": null,
  "scrapedAt": "2026-08-17T23:03:34+00:00"
}
```

Missing values are explicit `null`, so CSV and Excel exports always have the same columns.

### Use it from code or AI agents

```bash
curl -X POST "https://api.apify.com/v2/acts/worktech~hitta-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms":["rörmokare"],"locations":["Stockholm"],"maxResultsPerSearch":100}'
```

The actor also works with n8n, Make, Zapier, webhooks and the **Apify MCP server** — its flat, structured output is designed to be consumed by AI agents directly.

### Business-only by design

hitta.se runs two indexes: companies (`företag`) and private persons (`personer`). Personal data is not what a lead-generation tool should be shipping, so the person index is walled off in four independent layers:

1. **URL layer** — every URL the actor builds is pinned to the company tab (`typ=ftg`). There is no code path that can request a person search.
2. **Input layer** — a person URL in **Start URLs** (`typ=prv`, `/personer/`, `/person/`) is rejected before a single request is made, with a named error explaining why.
3. **Page layer** — any fetched page whose selected tab is not the company tab is discarded whole, not parsed.
4. **Record layer** — an entry carrying private-person markers (a split personal name, an age, birthday/gender attributes) is dropped even if it were to appear inside the company list.

Every such drop is counted and written to the run **SUMMARY** as `privatePersonEntriesDropped`, so each run carries its own evidence — the field is always present, including when it is `0`.

There is deliberately **no `includePersons` input**. The unit test suite includes a person-result fixture that the parser must refuse, and asserts that no input in the schema can re-enable persons.

### Why this scraper?

- **The search grammar that actually filters** — hitta.se silently ignores the legacy `var=` location parameter and answers with the nationwide list. This actor uses the form verified against the live site, so `rörmokare` + `Stockholm` really returns Stockholm companies (210 hits) instead of the national 3,447.
- **A real end-of-pagination signal** — it follows hitta.se's own next-page link and cross-checks it against the reported hit count, instead of guessing that "a full page means there's another one". No phantom pages, no wasted requests on the tail of a search.
- **Email and website included at the base price** — no detail-page crawl, no enrichment surcharge, no residential-proxy blow-up.
- **No silent failures** — a burned search is recorded as a named error in the run **SUMMARY** (including *which* status burned it — 403, 429 or a timeout) and never kills the other searches; a charge failure is never swallowed; and you are never billed for records you did not receive, because records are pushed before they are charged. If hitta.se ever renames the fields this scraper reads, the run **fails loudly** instead of handing you an empty dataset with a green tick.
- **Fast and cheap by construction** — plain HTTP, no headless browser, one page at a time by default.

Also from worktech: [Eniro Scraper — Swedish Business Directory Leads](https://apify.com/worktech/eniro-scraper) — pair it with this actor for wider Swedish coverage, and [Lean Shopify Scraper](https://apify.com/worktech/lean-shopify-scraper).

### FAQ

**Do I need an API key or a hitta.se account?**
No. You need a free Apify account; the actor needs no credentials of any kind, and it only reads pages that are public to any visitor.

**Can I export the leads to CSV or Excel?**
Yes. Every run produces a dataset downloadable as CSV, Excel, JSON, HTML or XML from the Apify Console, or via the API.

**Do I get email addresses?**
Yes, when hitta.se publishes one — email is part of the search result, so it costs nothing extra. Coverage varies a lot by market: measured on live pages, 19–24 of 25 companies in Stockholm-area searches had an email, against 3 of 11 in Kiruna. Companies without a published address get `email: null`.

**Does it collect private persons?**
No, and it cannot. See [Business-only by design](#business-only-by-design) — the person index is unreachable from every layer of the actor, and there is no setting to turn it on.

**What about sole traders listed under a personal-sounding name?**
Entries like "Mats Rörmokare" are *registered businesses* in hitta.se's company index — they carry no personal identity data (no age, no birthday, no personal number) and they are legitimate B2B leads, so they are kept. Records from the private-person index are a different thing entirely, and those never appear.

**Is this legal / GDPR-compliant?**
The actor collects publicly published **business** contact information — the same data any visitor to hitta.se sees — and structurally excludes private-person records. Under GDPR you still need your own lawful basis (for B2B prospecting this is usually legitimate interest) and you must honour opt-outs and Swedish marketing rules. You are the data controller for what you do with the export; when in doubt, consult a lawyer.

**What should I put in Search terms — Swedish or English?**
Swedish, matching hitta.se's own categories: `rörmokare` (plumber), `elektriker` (electrician), `tandläkare` (dentist), `redovisningsbyrå` (accounting firm), `frisör` (hairdresser).

**Which proxy should I use?**
**None — that's the default, and it's the cheapest option.** hitta.se does not geo-block or challenge this scraper, so runs go straight out with no proxy: roughly **$0.007 of traffic per 1,000 records**, against **~$0.021 per 1,000** on residential proxies. Only turn a proxy on if failed searches show up in the run SUMMARY, and then pick **Apify Proxy → RESIDENTIAL group, country SE** and raise the delay. Avoid a country-targeted **datacenter** proxy: on accounts without that entitlement it fails every request with `ProxyError: 407 Proxy Authentication Required`.

**Why do some records have no website?**
hitta.se only publishes a homepage link for companies that bought one. When there is none, `website` is `null` rather than a guess.

### Limitations

- **Coverage is whatever hitta.se publishes** — companies without a listed email or website come back with `null` in those fields.
- **One search term × location at a time** — pagination is walked in order with a politeness delay; very large nationwide sweeps take proportionally longer.
- **Pagination is capped at 200 pages (~5,000 records) per search combination** as a runaway guard — split large categories by city to get everything.
- **Search terms must be Swedish** — hitta.se matches its own category vocabulary; English words return few or no hits.
- **Records are per listing, not per organisation** — a company with several offices can appear more than once (each with its own address), which is usually what you want for local outreach.

### Status

**v0.1** — 150 unit tests passing against fixtures captured from the live site, covering parsing, the business-only guards, pagination termination, billing order and input validation. Every fixture in this repository was scrubbed of private-person payloads before it was committed.

# Actor input Schema

## `searchTerms` (type: `array`):

Business categories or keywords to search on hitta.se, in Swedish (e.g. rörmokare, elektriker, redovisningsbyrå, tandläkare). Each term is combined with every location below.

## `locations` (type: `array`):

Swedish cities, towns or municipalities to search in (e.g. Stockholm, Göteborg, Kiruna). Leave empty to search all of Sweden.

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

Paste hitta.se COMPANY search URLs directly, e.g. https://www.hitta.se/s%C3%B6k?vad=r%C3%B6rmokare%20stockholm\&typ=ftg — used instead of or in addition to search terms. Only company (företag) searches are accepted; any other hitta.se URL is rejected with a clear error.

## `maxResultsPerSearch` (type: `integer`):

Cap on business records per search term x location combination. 0 = no cap (scrapes every result page).

## `requestDelayMs` (type: `integer`):

Politeness delay between paginated search requests.

## `proxyConfiguration` (type: `object`):

No proxy is needed — hitta.se does not geo-block or challenge this scraper, and running without a proxy is both proven and about 3x cheaper (~$0.007 vs ~$0.021 of proxy traffic per 1,000 records). Only turn a proxy on if you see failed searches in the run SUMMARY, and then choose Apify Proxy with the RESIDENTIAL group and country SE — a country-targeted DATACENTER proxy fails with 'ProxyError: 407 Proxy Authentication Required' on accounts without that entitlement.

## Actor input object example

```json
{
  "searchTerms": [
    "rörmokare"
  ],
  "locations": [
    "Stockholm"
  ],
  "maxResultsPerSearch": 100,
  "requestDelayMs": 1000,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `businessRecords` (type: `string`):

No description

# 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 = {
    "searchTerms": [
        "rörmokare"
    ],
    "locations": [
        "Stockholm"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("worktech/hitta-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 = {
    "searchTerms": ["rörmokare"],
    "locations": ["Stockholm"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("worktech/hitta-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 '{
  "searchTerms": [
    "rörmokare"
  ],
  "locations": [
    "Stockholm"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call worktech/hitta-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,worktech/hitta-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/v0n6GP4spCZdPvgAW/builds/IZfY859Cx6FNUDFja/openapi.json
