# Xero Advisors Scraper (`normdata/xero-advisors-scraper`) Actor

Every Xero-certified accounting and bookkeeping firm in 86 countries: partner tier, phone, website, every office, badges and professional bodies. Emails from each firm's own site, 13 filters, search near any city, one row per firm or office, and alerts on new firms and tier changes.

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

## Pricing

from $7.00 / 1,000 firms

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

![Norm Data](https://raw.githubusercontent.com/FabriAV/normdata/refs/heads/main/assets/banner_norm.png)

## 🧾 Xero Advisor Directory Scraper

Get every **Xero-certified accounting and bookkeeping firm** from Xero's official advisor directory: more than 17,000 firms in 86 countries. Each firm comes with its **Xero partner tier**, the year it became a partner, phone, website, every office with its address and coordinates, specialist badges, certifications, professional bodies, and social links. Turn on email finding to add the public emails from each firm's own website. No login, no account.

Built for B2B sales, partnerships, and market research teams that sell to accountants and bookkeepers.

### 🎯 Who uses it?

#### 🤝 SaaS and fintech sales teams

Build account lists of firms that already run a cloud accounting stack: payroll, expenses, lending, practice management, AP and AR tools. The partner tier is a ready-made size signal.

#### 🔌 App partners and integrators

Find the firms that recommend apps to their clients, by country, region, industry served, and specialty.

#### 🏢 Recruiting, M\&A, and roll-ups

Source practices by market, tier, office count, team size, and how long they have been Xero partners.

#### 📊 Market research

Map the Xero partner ecosystem by country, region, tier, and specialty, and track it over time with alerts.

### ✨ What it does

- **The whole directory:** every firm in all 86 countries, including firms that list no office address, which are placed by their phone code and website instead of being missed.
- **Complete results:** big searches are split automatically, so you get every match and not just the first 5,000.
- **13 filters:** country, city, state or postcode, distance around a city, keywords, partner tier, industries served, specialist badges, certifications, professional bodies, partner-since year range, minimum offices, minimum team size, and must-have contact details.
- **Emails from the firm's own site:** only addresses on the firm's own domain (or its personal mailbox), each marked as a role mailbox or a named person, with a check that the domain receives mail.
- **One row per firm or one row per office,** for territory planning and field sales.
- **Alerts:** schedule the same search and each run returns only new firms, or also tier upgrades and downgrades, offices opened or closed, team changes, and firms that left the directory.

Missing source values are returned as `null`, never invented.

### Why this scraper

- **All 86 countries,** not a short list.
- **Nobody is missed:** firms without an office address are placed by country too, instead of disappearing from country searches.
- **Filters the others skip:** specialist badges, certifications, professional bodies, partner-since years, office count, team size, and distance around a city.
- **Clean emails:** addresses that belong to someone else (a web agency, another brand) are left out, so outreach reaches the firm.
- **Alerts that say what changed:** a tier upgrade comes with the tier before, and firms that left the directory are reported too. A firm leaving Xero is a strong signal for competing platforms.
- **Phones ready to dial,** in international format, and every office's phone and address.

### How it compares

| Capability | This actor | Other Xero advisor scrapers |
|---|:--:|:--:|
| Firm name, tier, phone, website, address | yes | yes |
| **All 86 countries** | **yes** | 25 |
| **Firms without an office address placed by country** | **yes** | no |
| **Badge, certification, and professional body filters** | **yes** | no |
| **Partner-since year, office count, and team size filters** | **yes** | no |
| **Distance around a city** | **yes** | no |
| **Only emails on the firm's own domain** | **yes** | no |
| **One row per office** | **yes** | no |
| **Alerts for tier changes, offices, and firms leaving** | **yes** | new firms only |

### 📦 What data you get

| Entity | Useful fields |
| --- | --- |
| Firm | ID, name, description, Xero partner tier, partner-since year, office count, team size, industries served, specialist badges, certifications, and professional bodies. |
| Location | Country (and every country with an office), state or region, city, postcode, street, coordinates, distance from your point, and every office with its own address and phone. |
| Contact | Phone in international format, all phones, email and all emails found, email type, whether the email domain receives mail, website, and domain. |
| Online | Xero profile link, LinkedIn, Facebook, X, video, and logo. |
| Team | Team members with name, job title, and short bio (optional). |
| Alerts | What changed since the last run and the tier before. |

Every record includes `scraped_at` (UTC). Download your dataset from Apify as CSV, JSON, Excel, or XML.

### 💡 Use cases

#### 🤝 Platinum and Gold firms in Texas with a phone and website

```json
{ "countries": ["US"], "locations": ["Texas"], "tiers": ["PLATINUM", "GOLD"], "mustHave": ["phone", "website"] }
```

#### 📧 UK payroll specialists with an email, for outreach

```json
{ "countries": ["GB"], "specialties": ["Payroll specialist"], "findEmails": true, "mustHave": ["email"] }
```

#### 🏗️ Australian firms serving construction, within 25 km of Sydney

```json
{ "countries": ["AU"], "industries": ["Construction and trades"], "nearCity": "Sydney", "radiusKm": "25" }
```

#### 🏢 Multi-office practices for M\&A sourcing, one row per office

```json
{ "countries": ["NZ"], "minOffices": 3, "outputMode": "office" }
```

#### 🆕 New Xero partners since 2025, with AICPA members

```json
{ "countries": ["US"], "partnerSinceFrom": 2025, "professionalBodies": ["American Institute of CPAs"] }
```

#### 🔔 Weekly alerts on new firms and tier changes in Ireland

```json
{ "countries": ["IE"], "alertMode": "changes" }
```

### ⚙️ How the input is organised

**Maximum firms** sits at the very top. It is 10 (prefilled) so a first run is a quick sample; clear it to collect every match. Below it, the form is split into five numbered sections:

| Section | What it's for |
| --- | --- |
| **1 · Where** | Countries, cities, states or postcodes, and distance around a city. |
| **2 · Which firms** | Keywords, partner tiers, industries served, badges, and professional bodies. |
| **3 · Size and experience** | Partner-since years, minimum offices, and minimum team size. |
| **4 · Contact details** | Must-have details, email finding, and team members. |
| **5 · Output and alerts** | One row per firm or per office, and alerts. |

> **Apify Free plan:** every run is limited to a fixed 10-row sample. Upgrade your Apify plan to run your own settings.

### ❓ FAQ

**How is a firm without an office address placed in a country?**
About one firm in six lists no physical office. Its country comes from its phone code (for +1 numbers, from the area code, so the United States, Canada, and the Caribbean are told apart) or, failing that, from its web domain. Those rows have `country_from_contact` set to true.

**Where do the emails come from?**
The directory itself rarely lists an email. With email finding on, each firm's own website is read (home page, then its contact page) for public addresses. Only addresses on the firm's own domain, or a personal mailbox such as Gmail, are kept. Each is marked as a role mailbox (info@, hello@) or a named person, and the domain is checked for mail servers.

**What does one row per office mean?**
Each office becomes its own row with its own address and phone, and the firm's details repeated. A firm is still charged once, however many offices it has.

**How do alerts work?**
The first run of a search returns its matches and remembers every firm with its tier, offices, and team size. Each later run of the exact same search returns only new firms, or also firms whose tier, offices, or team changed, and firms that left the directory.

**Why do some columns only appear sometimes?**
Columns that belong to an option (emails, team members, one row per office, distance, alerts) appear only when that option is on, so no column is empty on every row. The dataset has a ready view for each: Emails, Offices, Alerts, and Team.

**How fast is it?**
About 1,000 firms in around 15 seconds, and the whole directory in about two minutes. Email finding reads each firm's website, so it adds time.

### 🛡️ Limits & responsible use

This Actor reads only Xero's public advisor directory and, when asked, the public pages of each firm's own website. It never signs in and never contacts firms.

Firm details are business information. Team members are included only when you ask for them, with the name, job title, and bio the firm published on its own listing. Use the data for relevant business purposes and respect applicable privacy and anti-spam rules when you reach out.

### 📧 Contact

Need a scraper for a different site, or found something wrong with this one? norm.data.scrapers@gmail.com

### Local development

```bash
bun install
bun test
bun run src/main.ts
```

# Changelog

This Actor's version history is a separate document: https://apify.com/normdata/xero-advisors-scraper/changelog.md

# Actor input Schema

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

How many firms to return. 10 is a quick sample; clear it to get every match.

## `countries` (type: `array`):

Pick one or more countries (the number is how many firms each has). Leave empty for all 86.

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

Only firms with an office in these places, e.g. "Texas", "Austin", "London", "NSW", "2000".

## `nearCity` (type: `string`):

Only firms with an office around this city, e.g. "Sydney" or "Austin, US". Pick the distance below.

## `radiusKm` (type: `string`):

How far from "Near a city" an office can be.

## `tiers` (type: `array`):

Platinum and Gold firms are the biggest Xero partners. Leave empty for all.

## `industries` (type: `array`):

Firms that work with clients in any of these industries.

## `specialties` (type: `array`):

Xero badges the firm must hold, e.g. payroll specialist or tax expert. All the ones you pick are required.

## `professionalBodies` (type: `array`):

Firms that are members of any of these, e.g. AICPA, ICAEW, CPA Australia.

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

Words in the firm's name or description, e.g. "ecommerce", "CFO", "SMSF". Any of them matches.

## `partnerSinceFrom` (type: `integer`):

Only firms that joined Xero in or after this year, e.g. 2024 for new partners.

## `partnerSinceTo` (type: `integer`):

Only firms that joined Xero in or before this year, e.g. 2014 for long-time partners.

## `minOffices` (type: `integer`):

For bigger practices, e.g. 3.

## `minStaff` (type: `integer`):

Counts the team members the firm lists on Xero.

## `findEmails` (type: `boolean`):

Looks for the firm's email on its own website. Slower, and a firm with an email found costs a little extra. Adds the email, its type (like info@ or a person), and whether it can receive mail.

## `mustHave` (type: `array`):

Skip firms missing these, e.g. phone and website for cold calling.

## `includeStaff` (type: `boolean`):

Adds each team member's name, job title, and short bio.

## `outputMode` (type: `string`):

A firm with 3 offices gives 3 rows in office mode, and is still charged once.

## `alertMode` (type: `string`):

For scheduled runs: the first run returns everything, later runs only what is new or changed.

## Actor input object example

```json
{
  "maxItems": 10,
  "countries": [
    "US"
  ],
  "findEmails": false,
  "includeStaff": false,
  "outputMode": "firm",
  "alertMode": "all"
}
```

# Actor output Schema

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

One dataset row per listing.

# 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 = {
    "maxItems": 10,
    "countries": [
        "US"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/xero-advisors-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 = {
    "maxItems": 10,
    "countries": ["US"],
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/xero-advisors-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 '{
  "maxItems": 10,
  "countries": [
    "US"
  ]
}' |
apify call normdata/xero-advisors-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,normdata/xero-advisors-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/k8vlCkZ3eU3nBJlrn/builds/MxeyiFw6h4gDLwdK3/openapi.json
