# Alberta Auto Business License Lookup - AMVIC Register (`scrapersdelight/amvic-alberta-auto-register-scraper`) Actor

Scrape AMVIC's register of licensed Alberta automotive businesses - dealers, repair shops, body shops, recyclers and salvage. 8,297 active licences, 8,291 with an e-mail, every one with a renewal date, so you can target licences expiring in the next 30, 60 or 90 days. Phone, address and class too.

- **URL**: https://apify.com/scrapersdelight/amvic-alberta-auto-register-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.80 / 1,000 per licensed business returneds

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/actors/running/actors-in-store.md#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

## Alberta Auto Business License Lookup — AMVIC Register

Every business that sells, repairs, recycles or leases vehicles in Alberta must hold an **AMVIC**
licence, and that licence **expires on a fixed date**. This Actor exports the register: who is
licensed, what they are licensed to do, how to contact them, and **when their licence comes up for
renewal**.

That last field is the point. A directory tells you who exists; a renewal date tells you *when to
call*.

***

### What one row looks like

```json
{
  "registrationNumber": "B1041046",
  "name": "1010 TIRES.COM INC.",
  "tradeName": null,
  "licenceStatus": "Issued",
  "isActive": true,
  "entityType": "Corporation",
  "businessClasses": ["Service Station", "Mobile"],
  "street1": "37 Cottonwood Cresent",
  "city": "Calgary",
  "province": "AB",
  "postalCode": "T8L 0H8",
  "telephone": "780-885-9179",
  "email": "cldd2019@gmail.com",
  "website": null,
  "expiryDate": "2026-09-30",
  "daysUntilExpiry": 18
}
```

| field | what it is |
|---|---|
| `registrationNumber` | AMVIC's own licence number |
| `licenceStatus` · `isActive` | `Issued` means currently licensed |
| `businessClasses` | What they are licensed to do — Used Sales, Retail Sales, Wholesale, Auto Body, Garage, Service Station, Recycling and Dismantling, Leasing, Mobile, Specialty Service |
| `entityType` | The **legal entity** (Corporation, Sole Proprietorship…). Not a licence class — that's `businessClasses` |
| `expiryDate` · `daysUntilExpiry` | The renewal date, and how long is left |
| `email` · `telephone` · address | Contact details as filed with AMVIC |
| `province` · `provinceRaw` | Normalised code, plus exactly what the register said |

### Measured size — the honest numbers

The register holds 21,974 rows, but that figure oversells it. Measured 2026-09-11 on the **full**
register:

| | |
|---|---|
| **Currently licensed (`Issued`)** | **8,297** |
| — of those, with an e-mail | **8,291** (99.9%) |
| — of those, with a renewal date | **8,297** (100%) |
| Expired, closed or cancelled | 9,973 |
| Applications and refusals (no licence number, no status) | **3,667** — excluded by default |

Expiring soon, among active licences: **401 within 30 days · 1,052 within 60 · 1,665 within 90 ·
3,741 within 180**.

**A note on fill rates, because the register lies about them.** AMVIC writes the literal string
`"N/A"` into empty columns. Counted naively, `email` looks 99.8% filled. Treating `"N/A"` as empty —
which this Actor does, before anything is counted, filtered or charged — the true rates across all
21,974 rows are: **e-mail 82.6%, expiry 80.8%, registration number 83.3%, trade name 56.1%,
entity type 52.6%, website 20.1%**. An `"N/A"` in an e-mail column is how a scraper poisons a CRM.

### Input

| input | default | what it does |
|---|---|---|
| `licenceStatus` | `["Issued"]` | Currently-licensed only by default |
| `province` | `["AB"]` | Normalised, so `Alberta`, `ALBERTA` and `AB` all match |
| `city` | — | Case-insensitive. Calgary 2,179 · Edmonton 1,837 · Red Deer 206 |
| `expiringWithinDays` | `0` | **The renewal trigger** — e.g. 60 returns the 1,052 licences due inside two months |
| `requireEmail` | `false` | — |
| `includeUnlicensed` | `false` | See below |
| `includeBusinessClasses` | `true` | Adds licence classes. One extra request per delivered row, **never billed separately** |
| `maxRecords` | `1000` | Cap on delivered and charged rows |
| `proxyConfiguration` | Apify **RESIDENTIAL, CA** | See **Why residential** |

**Results come back soonest-expiry first.** That matters when you cap a run: you get the most
urgent licences, not whichever ones happened to sit at a low offset in the register.

#### Applications and refusals are excluded by default

3,667 register rows (16.7%) have **no licence number and no status**. They are applications and
refusals, not licensed businesses — and **230 of them put an individual's name and an adverse
outcome in the name field** (`"SABRIE, ABDEL-AZIZ (refused)"`, `"1776042 ALBERTA LTD. (Refusal)"`).
They are not business leads and they are filtered out unless you deliberately ask for them with
`includeUnlicensed`.

### Why residential

AMVIC's register sits behind AWS WAF, which matches on **User-Agent** *and* on IP reputation.
Measured 2026-09-11, same request, same correct desktop Chrome header:

| exit | passed |
|---|---|
| Residential, Canada | **10 / 10** |
| Home connection | 10 / 10 |
| Datacenter | **4 / 10** |

A rejected request returns **HTTP 405** with `x-amzn-waf-action: captcha`. That status is
misleading: it does not mean "method not allowed" and it does not mean "slow down" — it means the
client fingerprint was refused. This Actor pins a full desktop Chrome header, retries a bounded
number of times on a fresh session, and then **fails the run with that explanation** rather than
looping forever or delivering a half-register.

It also checks its own work: the register is only accepted if the number of records read matches the
count AMVIC itself declares. A short read fails the run instead of quietly shipping a smaller register.

### Pricing

Pay per event: **$0.0018 per `business-record`** — charged only for a row delivered to your dataset.
Licence classes are included in that price; the extra lookup that fetches them is never billed
separately. Filters are applied before delivery, so rows they drop are never charged, and a run that
returns nothing costs nothing.

A default run (1,000 rows) is **$1.80**; all 8,297 active licences is **$14.93**.

**Small runs are relatively dearer to produce.** The whole register has to be read before it can be
filtered, so a 25-row run costs about the same to run as a 1,000-row one. That is our cost, not your
price — but it is why this Actor defaults to 1,000 rows rather than 25.

Every run writes a `RUN_SUMMARY` with the register size against AMVIC's declared count, how many rows
were applications rather than licences, what the filters matched, delivered vs charged, and what
truncated the run.

### Source and legal

Data comes from AMVIC's public register at `amvic.ca.thentiacloud.net`, the register Albertans are
directed to in order to check whether a business is licensed. AMVIC publishes it under the *Consumer
Protection Act* and the *Automotive Business Regulation*.

`robots.txt` on that host reads, verbatim:

```
User-agent: *
Disallow: /
```

Many of the e-mail addresses are personal (gmail, shaw, telus) because a large share of Alberta's
licensed automotive businesses are owner-operators. They are published by the regulator, but they are
still personal data: Canadian anti-spam law (**CASL**) requires consent or a genuine business
relationship for commercial electronic messages, with real penalties. You are responsible for your
own compliance. This Actor deliberately does **not** return AMVIC's salespeople register, which is a
list of named individuals rather than businesses.

# Actor input Schema

## `licenceStatus` (type: `array`):

Measured counts: Issued 8,297 - Expired - Required to Reapply 5,200 - Closed - Voluntarily 4,469 - Expired 229 - Cancelled by Registrar 75. Defaults to currently-licensed businesses only.

## `province` (type: `array`):

Normalised before matching, so 'Alberta', 'ALBERTA' and 'AB' all count as AB. The register is 20,832 Alberta plus a small out-of-province tail (BC 40, ON 37, SK 7, MB 7).

## `city` (type: `array`):

Optional, case-insensitive. Largest active-licence cities: Calgary 2,179 - Edmonton 1,837 - Red Deer 206 - Lethbridge 174 - Grande Prairie 157.

## `expiringWithinDays` (type: `integer`):

The renewal trigger. Measured against active licences: 401 expire within 30 days, 1,052 within 60, 1,665 within 90, 3,741 within 180. 0 disables the filter.

## `requireEmail` (type: `boolean`):

8,291 of the 8,297 active licences carry one. Across the whole register including closed and expired records it is 82.6%.

## `includeUnlicensed` (type: `boolean`):

Off by default. 3,667 register rows (16.7%) have no registration number and no status - these are applications and refusals rather than licensed businesses, and 230 of them name an individual with '(refused)' in the name field. Turn this on only if you specifically need them.

## `includeBusinessClasses` (type: `boolean`):

Adds the AMVIC licence classes each business holds (Used Sales, Retail Sales, Wholesale, Auto Body, Recycling and Dismantling, Leasing, and so on). Costs one extra request per delivered row and is never charged separately. Salespeople are deliberately not read.

## `maxRecords` (type: `integer`):

Hard cap on delivered - and therefore charged - rows, applied after sorting by soonest expiry. 0 means every match. Default 1,000 so a first run cannot bill for the whole register by accident.

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

Apify Proxy, RESIDENTIAL with a Canadian exit. AMVIC sits behind AWS WAF: measured 2026-09-11, residential-CA passed 10 of 10 requests where datacenter passed 4 of 10.

## Actor input object example

```json
{
  "licenceStatus": [
    "Issued"
  ],
  "province": [
    "AB"
  ],
  "city": [],
  "expiringWithinDays": 0,
  "requireEmail": false,
  "includeUnlicensed": false,
  "includeBusinessClasses": true,
  "maxRecords": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per licensed Alberta automotive business - identity and registration number, licence status and class, full address, phone and e-mail, and the renewal date with days remaining. Sorted soonest-expiry first, so a capped run returns the most actionable licences.

## `runSummary` (type: `string`):

RUN\_SUMMARY: register size against the count AMVIC declares, how many rows were applications rather than licences, what the filters matched, delivered vs charged, how many carry an e-mail and an expiry, and what truncated the run.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/amvic-alberta-auto-register-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/amvic-alberta-auto-register-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 '{}' |
apify call scrapersdelight/amvic-alberta-auto-register-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/amvic-alberta-auto-register-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/6bmG2R26uuPxeIOOz/builds/V9qTUaSrvBwvienaq/openapi.json
