# Berlin Startup Jobs Scraper (`zerobreak/berlin-startup-jobs-scraper`) Actor

Berlin Startup Jobs Scraper collects startup job listings in Berlin, helping users discover relevant career opportunities efficiently. It extracts available job details, organizes results into structured data, and simplifies job research for developers, professionals, and job seekers.

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

## Pricing

from $2.99 / 1,000 results

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

## Berlin Startup Jobs Scraper: Berlin startup jobs RSS

<p align="center">
  <img src="https://i.imgur.com/mMR43YS.jpeg" alt="Berlin Startup Jobs Scraper" style="max-width:100%; border-radius:14px; width:680px;" />
</p>

Berlin Startup Jobs Scraper collects berlin startup jobs RSS items from the public Berlin Startup Jobs feed. It needs no login, no API key, and no proxy. Each run exports a short job list as JSON, CSV, or Excel so you can refresh Berlin role lists on a schedule.

The actor reads `https://berlinstartupjobs.com/feed/` and older pages with `?paged=N`. It keeps the headline, link, date, author, categories, and a short summary. It does not download full job articles.

### Features

- Reads the public RSS feed directly, with no account and no API key.
- Keeps headline, link, date, author, categories, and a short plain-text summary.
- Optional keyword filter on the title and summary.
- Deduplicates rows by `guid` so scheduled runs do not repeat items.
- Retries HTTP 429 and 5xx with backoff and honours `Retry-After`.
- Pushes an error row instead of crashing when a feed URL fails, so the run still finishes.

### Use cases

- **Berlin startup jobs RSS**: pull the latest public openings into a dataset without an account
- **Hiring research**: filter titles and summaries for a keyword such as payroll or support
- **Scheduled export**: refresh the same feed on a timer and dedupe rows by guid
- **CSV and JSON**: download the dataset for a sheet, a CRM, or a weekly digest
- **Free monitoring**: stay within a 1000 row cap and a direct request, with no API key

### Input

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `feedUrls` | array | `https://berlinstartupjobs.com/feed/` and page 2 | Berlin Startup Jobs RSS URLs. Only the `/feed/` path, with an optional `paged` query, is accepted. |
| `keyword` | string | empty | Optional filter. A row is kept when this text appears in the job title or the short summary. |
| `maxItems` | integer | 100 | Maximum successful job rows. Hard max 1000. |
| `timeoutSecs` | integer | 300 | Stop starting new feed requests after this many seconds. Maximum 3600. |
| `requestTimeoutSecs` | integer | 30 | Seconds to wait for each RSS response. |
| `proxyConfiguration` | object | `{"useApifyProxy": false}` | Optional proxy. Leave the default off. The public feed does not need a proxy. |

#### Example input

```json
{
  "feedUrls": [
    "https://berlinstartupjobs.com/feed/",
    "https://berlinstartupjobs.com/feed/?paged=2"
  ],
  "keyword": "",
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

### What data does this actor extract?

Each job row looks like this:

```json
{
  "jobTitle": "Customer Support Specialist (m/w/d) // TAXMARO",
  "link": "https://berlinstartupjobs.com/operations/customer-support-specialist-m-w-d-taxmaro/",
  "author": "BSJ-Admin2",
  "pubDate": "Thu, 08 Oct 2026 10:39:03 +0000",
  "categories": ["Operations & Support", "Customer Success", "Saas"],
  "guid": "https://berlinstartupjobs.com/de/?p=453015",
  "summaryText": "Die Rolle Damit unsere Kund:innen das volle Potenzial von Taxmaro nutzen. Read more",
  "sourceUrl": "https://berlinstartupjobs.com/feed/",
  "scrapedAt": "2026-10-12T03:41:00+00:00"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `jobTitle` | string | Job headline from the RSS title. |
| `link` | string | Public job page URL. Link back to this page when you reuse a listing. |
| `author` | string | Feed author. Null when the item has none. |
| `pubDate` | string | Publication date from the feed. Null when missing. |
| `categories` | array | Category labels from the item. |
| `guid` | string | Stable id used to drop duplicates. |
| `summaryText` | string | Short plain-text summary. HTML is stripped. Full article text is not stored. |
| `sourceUrl` | string | Feed URL that returned the item. |
| `scrapedAt` | string | UTC time the row was saved. |
| `error` | string | Present on failure rows instead of a job. |
| `input` | string | The feed URL or other value tied to an error row. |

A bad URL, an HTML error page, or a non-RSS body becomes an error row. The run still finishes.

### How it works

1. Read feed URLs, an optional keyword, and the item cap.
2. Request only `https://berlinstartupjobs.com/feed/` and `?paged=N` with a descriptive User-Agent.
3. Parse RSS items, strip HTML from the short summary, and skip full article markup.
4. Drop duplicates by guid, apply the keyword filter, and stop at `maxItems`.
5. When a page still has new jobs and the cap is not filled, request the next `paged` URL.
6. Retry HTTP 429, 5xx, and timeouts up to three times, waiting 2, 4, then 8 seconds, and honour `Retry-After`.
7. Wait about one second between feed requests. Schedule the actor every 5 to 15 minutes rather than polling faster.

### Troubleshooting

- **"Feed URL is not a verified Berlin Startup Jobs RSS endpoint"**: only `https://berlinstartupjobs.com/feed/` and the same path with `?paged=N` are accepted. Check the URL in `feedUrls`.
- **"Response was HTML, not an RSS feed"**: the site returned a block or error page instead of the feed. Try again later, and keep requests gentle by scheduling runs a few minutes apart.
- **"No items matched the keyword filter"**: the keyword did not appear in any title or summary. Clear it or use a broader term.
- **"Stopped because timeoutSecs was reached"**: raise `timeoutSecs`, or lower `maxItems` so the run finishes sooner.
- **Empty dataset**: the feed only carries recent items. Schedule regular runs and rely on guid dedupe to build history over time.
- **Rate limiting (HTTP 429)**: the actor already retries with backoff and honours `Retry-After`. Do not poll faster than every few minutes.

### Limits and terms

No terms page was available on the source site. Keep the job `link` when you share a listing. The feed only carries recent items, so scheduling plus guid dedupe is the way to watch for new roles. Output is the headline, link, date, and a short summary. Do not treat the dataset as a copy of the full post. Requests use one at a time with a one second gap. Retries cover 429 and 5xx. The free cap is 1000 items per run.

### FAQ

**Does the Berlin startup jobs RSS actor need an API key?**
No. The public feed is read with no login, no cookie, and no API key.

**How many Berlin jobs can one run export?**
`maxItems` defaults to 100 and cannot go above 1000. Page 2 and later pages are requested only while that cap is still open.

**Does it store the full job article?**
No. `summaryText` is the short RSS summary with tags removed. Article HTML from the content module is ignored.

**What happens if a feed URL is wrong?**
The actor pushes an error row with `error` and `input`, then continues with any valid feeds. The run succeeds.

**Is the proxy required?**
No. `proxyConfiguration` defaults to `useApifyProxy` false and is optional.

#### Trademark Notice

Berlin Startup Jobs and related names, logos, and trademarks belong to their respective owners. Their use in this documentation is solely to identify the source of the data and does not imply affiliation, sponsorship, endorsement, or partnership.

#### Disclaimer

Disclaimer: This Actor is an independent tool and is not affiliated with, endorsed by, sponsored by, or otherwise officially associated with Berlin Startup Jobs or its owners. All data is collected from publicly available sources. Users are responsible for complying with the source's terms of use, rate limits, and attribution or licensing requirements.

#### Is web scraping legal?

This Actor only collects publicly available data from Berlin Startup Jobs, mostly through its public feed, without logging in or bypassing any access controls. Scraping public data is generally legal, but how you use it matters:

- **Personal data:** If the results include personal data (for example names, emails, or profile details), laws such as the GDPR in the EU and the CCPA in California may apply. Only collect and store personal data when you have a legitimate reason.
- **Copyright:** Some content (articles, images, descriptions) may be protected by copyright. Do not republish full copyrighted content without permission.
- **Terms of use:** Respect the source's terms, stated rate limits, and any attribution or non-commercial-use requirements listed in the Limits and terms section.
- **Legal advice:** This is general information, not legal advice. If you're unsure, consult a lawyer.

To learn more, read Apify's guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

## `feedUrls` (type: `array`):

Berlin Startup Jobs RSS feed URLs. Only https://berlinstartupjobs.com/feed/ and the same path with ?paged=N are accepted.

## `keyword` (type: `string`):

Optional client-side filter. A row is kept when this text appears in the job title or the short summary. Leave blank to keep every item.

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

Maximum successful job rows to save. Free cap, hard max 1000.

## `timeoutSecs` (type: `integer`):

Stop starting new feed requests after this many seconds. Default 300. Maximum 3600.

## `requestTimeoutSecs` (type: `integer`):

Seconds to wait for each RSS response before retrying.

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

Optional proxy for feed requests. Leave useApifyProxy off. The public RSS feed does not need a proxy.

## Actor input object example

```json
{
  "feedUrls": [
    "https://berlinstartupjobs.com/feed/",
    "https://berlinstartupjobs.com/feed/?paged=2"
  ],
  "keyword": "",
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `datasetUrl` (type: `string`):

API URL for the default dataset of this run.

## `datasetItemsUrl` (type: `string`):

Item list for the default dataset.

## `overviewUrl` (type: `string`):

Overview table of Berlin startup job rows.

# 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 = {
    "feedUrls": [
        "https://berlinstartupjobs.com/feed/",
        "https://berlinstartupjobs.com/feed/?paged=2"
    ],
    "keyword": "",
    "maxItems": 100,
    "timeoutSecs": 300,
    "requestTimeoutSecs": 30,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zerobreak/berlin-startup-jobs-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 = {
    "feedUrls": [
        "https://berlinstartupjobs.com/feed/",
        "https://berlinstartupjobs.com/feed/?paged=2",
    ],
    "keyword": "",
    "maxItems": 100,
    "timeoutSecs": 300,
    "requestTimeoutSecs": 30,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("zerobreak/berlin-startup-jobs-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 '{
  "feedUrls": [
    "https://berlinstartupjobs.com/feed/",
    "https://berlinstartupjobs.com/feed/?paged=2"
  ],
  "keyword": "",
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call zerobreak/berlin-startup-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zerobreak/berlin-startup-jobs-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/7GSEdskxmn28LYz8c/builds/xgie4p3AH3NfqXbNV/openapi.json
