# Doing Good Leeds Jobs Scraper - Charity Vacancies (`benthepythondev/doinggoodleeds-jobs-scraper`) Actor

Scrape public Leeds and Yorkshire third-sector jobs with employer, location, type, salary, added date, closing date, logo and vacancy URL.

- **URL**: https://apify.com/benthepythondev/doinggoodleeds-jobs-scraper.md
- **Developed by:** [Ben](https://apify.com/benthepythondev) (community)
- **Categories:** Jobs, Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 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.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Doing Good Leeds Jobs Scraper - Charity and Third-Sector Vacancies

Collect public charity, nonprofit, community, and third-sector vacancies from
Doing Good Leeds in a structured Apify dataset. The Actor returns the job title,
organization, location, employment type, public salary text, added date, closing
date, vacancy URL, organization logo, source URL, and collection timestamp from
the site's public job cards.

This Actor is designed for local job alerts, nonprofit recruitment research,
regional labor-market analysis, vacancy aggregation, and recurring third-sector
hiring feeds. It uses the server-rendered public jobs page, requires no account
or external API key, and exports results to JSON, CSV, Excel, XML, RSS, or the
standard Apify API.

### What this Actor returns

Each default-dataset item is one public vacancy card with clear source
provenance:

- `title`: the displayed job title;
- `organization`: the hiring charity, community group, or organization;
- `location`: the public location label, such as Leeds or West Yorkshire;
- `employment_type`: the displayed full-time or part-time label;
- `salary_text`: the published salary or `See details` when the card does not
  contain a numeric amount;
- `added_text`: the date text shown after `ADDED`;
- `closing_text`: the application-closing date text;
- `url`: the direct public vacancy page;
- `organization_logo`: the public logo image when the card includes one;
- `search_url`: the search page that produced the result;
- `source`: `Doing Good Leeds`;
- `scraped_at`: the UTC timestamp of collection.

The Actor does not invent normalized salaries or dates when the source provides
only display text. This preserves fidelity and avoids false precision.

### Use cases

#### Daily local job alerts

Run the Actor each morning, compare vacancy URLs against the previous dataset,
and send only newly seen roles to email, Slack, Telegram, or a spreadsheet. The
closing-date field helps recipients prioritize applications.

#### Charity and nonprofit job aggregation

Add Leeds and Yorkshire third-sector vacancies to a broader jobs product while
retaining the original source and direct application page. Use the URL as the
primary deduplication key.

#### Hiring-signal research

Track which local organizations are recruiting, the kinds of roles advertised,
and the locations or employment types shown publicly. This can support nonprofit
ecosystem research, workforce planning, or market reports.

#### Recruitment operations

Import current vacancies into an internal review sheet or database. Filter on
organization, location, employment type, salary text, or closing date before a
human decides which roles are relevant.

#### Historical vacancy monitoring

Schedule regular runs and retain snapshots to build a first-seen/last-seen
history downstream. The Actor reports the current page; it does not claim that
an absent card has been filled rather than removed or expired.

### Input

The default input points to Doing Good Leeds' public job search and returns no
more than ten records for a quick first run.

```json
{
  "searchUrls": ["https://doinggoodleeds.org.uk/search-jobs/"],
  "maxResults": 10
}
````

#### Input fields

- `searchUrls`: one or more public Doing Good Leeds job-search URLs. If the site
  exposes filters in the URL, configure them in the browser and paste the result.
  Up to 20 URLs are processed in one run.
- `maxResults`: maximum unique vacancies stored for each input URL, from 1 to
  100\. The source can return fewer rows than requested.

For clean recurring workflows, save one Apify task per distinct audience or
filter rather than combining unrelated searches.

### Example output

```json
{
  "title": "Community Development Worker",
  "organization": "Leeds GATE",
  "location": "West Yorkshire",
  "employment_type": "Full Time",
  "salary_text": "£27,097",
  "added_text": "11 June",
  "closing_text": "10 July",
  "url": "https://doinggoodleeds.org.uk/job/community-development-worker-11/",
  "organization_logo": "https://cdn-doinggood.b-cdn.net/example-logo.png",
  "search_url": "https://doinggoodleeds.org.uk/search-jobs/",
  "source": "Doing Good Leeds",
  "scraped_at": "2026-07-10T12:00:00+00:00"
}
```

Example values illustrate the schema. Live titles, organizations, salary text,
dates, and URLs change as vacancies are added or closed.

### Pricing and cost control

The Actor uses pay per event pricing:

- a small Actor-start event is charged once when a run begins;
- the `result` event is charged for each vacancy written to the default dataset.

The `maxResults` input provides a visible result ceiling. If one URL has a limit
of 10, no more than ten unique vacancy rows from that URL are stored. Duplicate
vacancy URLs across supplied searches are written only once per run. Apify
platform usage is displayed separately.

### Run through the API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/benthepythondev~doinggoodleeds-jobs-scraper/runs?token=$APIFY_TOKEN" \
  -H "content-type: application/json" \
  -d '{"searchUrls":["https://doinggoodleeds.org.uk/search-jobs/"],"maxResults":10}'
```

Keep the API token out of code repositories. The run response includes links to
the default dataset, and the Actor works with standard Apify tasks, schedules,
webhooks, and integrations.

### Automation ideas

- Run every weekday and append only unseen vacancy URLs to Google Sheets.
- Notify a Slack or Telegram channel when a matching title appears.
- Filter by closing-date text before sending a daily email digest.
- Combine this source with StepStone, XING, InfoJobs, or ATS feeds in a normalized
  regional hiring pipeline.
- Track organization hiring frequency in a private research database.
- Archive monthly datasets for nonprofit labor-market analysis.

When parsing display dates downstream, add the appropriate year and timezone
carefully. A card can omit the year because the website displays it in current
page context.

### Reliability and data quality

Doing Good Leeds currently serves semantic, server-rendered `job-card` elements.
The Actor parses those cards directly, retries transient request failures,
deduplicates vacancy URLs, and fails when the page contains no usable jobs. This
explicit failure prevents a redesigned or blocked source from appearing healthy
with an empty dataset.

The default input is small enough for Apify's routine testing and normal
interactive use. The output schema and dataset view keep the Actor useful for
both human inspection and agent/API workflows. Because the source is operated by
a third party, page structure, vacancy availability, and access behavior can
change without notice.

### Responsible use

Use public vacancy data for legitimate job discovery, aggregation, research, or
internal operations. Keep direct source links and verify important details on the
original vacancy page before applying, publishing, or making decisions. Respect
the source's terms, applicable copyright, privacy, employment, and database
rules. Do not use organization or applicant data for harassment, discrimination,
or unsolicited bulk messaging.

The Actor collects public job cards only. It does not submit applications,
collect applicant data, access employer accounts, or bypass logins.

### Limitations

- The Actor returns the public search-card fields, not every detail on each job
  page.
- Salary can be descriptive or `See details`; no numeric salary is fabricated.
- Display dates may omit a year and are therefore preserved as source text.
- A missing card can mean expiration, removal, a changed filter, or a source
  issue; downstream history should not assume the reason.
- Logo URLs remain controlled by the source CDN.
- The public page can contain fewer jobs than the configured result maximum.

### Frequently asked questions

#### Does this require a Doing Good Leeds account?

No. The Actor reads public vacancy cards without logging in.

#### Can I collect only a few jobs for testing?

Yes. Set `maxResults` to 1, 2, or another small value. The default is 10.

#### Does it include the application deadline?

It returns the public `closing_text` shown on the card. Verify the final deadline
and application instructions on the linked vacancy page.

#### Can it normalize salary to a number?

Not safely for every listing. Some cards show a numeric salary while others show
`See details`. The Actor preserves the source text so a downstream process can
apply rules appropriate to its use case.

#### Can I schedule daily alerts?

Yes. Save the input as an Apify task, schedule it, and trigger a webhook or
integration when the run finishes. Deduplicate alerts by vacancy URL.

#### What should I include in a support issue?

Share the run ID, non-secret input URL, expected job title, and the incorrect or
missing field. Never share an API token in a public issue.

### Related Actors

- [Remote Jobs Aggregator](https://apify.com/benthepythondev/remote-jobs-aggregator)
  for multi-source remote vacancies.
- [StepStone Scraper](https://apify.com/benthepythondev/stepstone-scraper) for
  European job-board research.
- [XING Jobs Scraper](https://apify.com/benthepythondev/xing-jobs-scraper) for
  public DACH job listings.
- [InfoJobs Jobs Scraper](https://apify.com/benthepythondev/infojobs-jobs-scraper)
  for public Spanish job listings.

If this Actor provides useful data, a short honest Store review helps other
users evaluate it. Reproducible issues receive faster support when the report
includes a run ID and the exact non-secret search URL.

**Keywords:** Doing Good Leeds scraper, Doing Good Leeds jobs API, Leeds charity
jobs scraper, Yorkshire nonprofit vacancies, third sector jobs data, community
jobs feed, charity recruitment API, UK nonprofit jobs, Apify jobs Actor.

# Actor input Schema

## `searchUrls` (type: `array`):

Paste Doing Good Leeds search URLs with the filters you want to collect.

## `maxResults` (type: `integer`):

Maximum unique vacancy cards returned for each search URL.

## Actor input object example

```json
{
  "searchUrls": [
    "https://doinggoodleeds.org.uk/search-jobs/"
  ],
  "maxResults": 10
}
```

# Actor output Schema

## `results` (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 = {
    "searchUrls": [
        "https://doinggoodleeds.org.uk/search-jobs/"
    ],
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("benthepythondev/doinggoodleeds-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 = {
    "searchUrls": ["https://doinggoodleeds.org.uk/search-jobs/"],
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("benthepythondev/doinggoodleeds-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchUrls": [
    "https://doinggoodleeds.org.uk/search-jobs/"
  ],
  "maxResults": 10
}' |
apify call benthepythondev/doinggoodleeds-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=benthepythondev/doinggoodleeds-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Doing Good Leeds Jobs Scraper - Charity Vacancies",
        "description": "Scrape public Leeds and Yorkshire third-sector jobs with employer, location, type, salary, added date, closing date, logo and vacancy URL.",
        "version": "1.0",
        "x-build-id": "uuSngSNWfnlT1UAdK"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/benthepythondev~doinggoodleeds-jobs-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-benthepythondev-doinggoodleeds-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/benthepythondev~doinggoodleeds-jobs-scraper/runs": {
            "post": {
                "operationId": "runs-sync-benthepythondev-doinggoodleeds-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/benthepythondev~doinggoodleeds-jobs-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-benthepythondev-doinggoodleeds-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchUrls": {
                        "title": "Doing Good Leeds job search URLs",
                        "type": "array",
                        "description": "Paste Doing Good Leeds search URLs with the filters you want to collect.",
                        "default": [
                            "https://doinggoodleeds.org.uk/search-jobs/"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "Maximum jobs per URL",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum unique vacancy cards returned for each search URL.",
                        "default": 10
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
