# Canada Gazette Regulatory Monitor (`peterdrucker481/canada-gazette-regulatory-monitor`) Actor

Monitor official Canada Gazette Part I/II regulatory changes and consultation deadlines as structured, webhook-ready data from public Government of Canada sources.

- **URL**: https://apify.com/peterdrucker481/canada-gazette-regulatory-monitor.md
- **Developed by:** [Peter Drucker](https://apify.com/peterdrucker481) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / actor start

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

## Canada Gazette Regulatory Change & Consultation Deadline Monitor

An Apify Actor that turns official Canada Gazette publications into structured, filterable, webhook-ready JSON. It monitors proposed regulations and notices in Part I, enacted regulations and statutory instruments in Part II, and the exact deadlines listed on the open-consultations page.

The Actor uses only public Government of Canada sources. It does not log in, submit consultation comments, bypass access controls, or collect private data.

### Official sources

| Source | Exact endpoint | Use |
|---|---|---|
| Canada Gazette Part I RSS | `https://www.gazette.gc.ca/rss/p1-eng.xml` | Discover weekly Part I issues containing notices and proposed regulations |
| Canada Gazette Part II RSS | `https://www.gazette.gc.ca/rss/p2-eng.xml` | Discover Part II issues containing enacted regulations and statutory instruments |
| Open consultations | `https://gazette.gc.ca/consult/consult-eng.html` | Read current proposed-regulation consultation periods and closing timestamps |

The Canada Gazette's [official RSS instructions](https://gazette.gc.ca/rss/sc-rb-eng.html) identify the Part I and Part II feeds. The [open-consultations page](https://gazette.gc.ca/consult/consult-eng.html) is the authoritative deadline source used by this Actor.

### What each record contains

- Stable `id`, canonical Government of Canada `sourceUrl`, Gazette part, publication date, and source list.
- `classification`: `proposed`, `final`, or `notice`.
- Department/agency, statutory authority, SOR/SI registration number, and a concise source summary when available.
- Normalized ISO 8601 `deadline`, `deadlineKind`, consultation length, and `daysRemaining`.
- Case-insensitive keyword matches.
- Deterministic `priorityScore` and `priority` band.
- `changeType`, first/last seen timestamps, and a deterministic fingerprint.
- A `webhook` envelope with an event name, deduplication key, timestamp, and compact payload.

### Example input

```json
{
  "keywords": ["bank", "privacy", "money laundering"],
  "keywordMode": "any",
  "parts": ["I", "II"],
  "includeConsultations": true,
  "includeNotices": true,
  "onlyNewOrChanged": true,
  "maxIssuesPerPart": 2,
  "maxItems": 250
}
```

Leave `keywords` empty to include every record. Set `onlyNewOrChanged` to `false` for a complete point-in-time export. The default named key-value store preserves fingerprints across Actor runs; set a different `stateKey` to create an independent monitoring stream.

### Example output record

```json
{
  "id": "gazette:5e9f…",
  "title": "Consumer-Driven Banking Regulations",
  "classification": "proposed",
  "part": "I",
  "publicationDate": "2026-06-27",
  "deadline": "2026-08-26T23:59:00-04:00",
  "deadlineKind": "consultation",
  "daysRemaining": 14,
  "consultationDays": 60,
  "department": "Department of Finance Canada",
  "statutoryAuthority": "Consumer-Driven Banking Act",
  "sourceUrl": "https://gazette.gc.ca/rp-pr/p1/2026/2026-06-27/html/reg3-eng.html",
  "matchedKeywords": ["bank"],
  "priorityScore": 72,
  "priority": "high",
  "changeType": "new",
  "webhook": {
    "eventType": "canada_gazette.record.new",
    "deduplicationKey": "gazette:5e9f…:<fingerprint>",
    "occurredAt": "2026-08-12T14:00:00.000Z",
    "payload": {
      "title": "Consumer-Driven Banking Regulations"
    }
  }
}
```

### Priority scoring

The score is deterministic and capped from 0 to 100:

- Base: final regulation `50`, proposed regulation `40`, notice `20`.
- Deadline: `+35` within 3 days, `+30` within 7, `+22` within 14, `+14` within 30, `+7` within 60, or `-10` when expired.
- Keyword relevance: `+5` per matched keyword, capped at `+20`.
- Change signal: `+10` for changed, `+5` for new, `0` for unchanged.
- Bands: urgent `80–100`, high `60–79`, medium `40–59`, low `0–39`.

Because all rules are explicit, the same record, reference time, keyword set, and state produce the same score.

### Stateful new/changed detection

Each record gets a stable ID from its canonical source URL and a SHA-256 fingerprint of its substantive fields and normalized source content. A persistent named Apify key-value store records the previous fingerprint:

- No prior ID: `new`
- Same ID, different fingerprint: `changed`
- Same ID, same fingerprint: `unchanged`

`onlyNewOrChanged: true` suppresses unchanged dataset items. The state is still updated for all discovered records. Stored entries not observed for two years are pruned, and the state is capped at 10,000 records.

### Webhooks and schedules

Schedule the Actor weekly after the Part I publication window and every second Wednesday after Part II is published, or run it daily for deadline monitoring. Each dataset item contains a self-contained webhook event envelope. Apify webhooks, the API, Make, Zapier, or another consumer can pass the dataset item downstream and deduplicate on `webhook.deduplicationKey`.

### Local development

Requirements: Node.js 22 or newer and pnpm.

```bash
pnpm install
pnpm check
pnpm start:dev
```

Local Apify storage is written under `storage/` and ignored by Git. Run `pnpm test:live` to verify that the three official endpoints remain reachable and parseable.

### Deployment

The `.actor` directory contains the current Actor definition, multi-stage Node.js 24 Dockerfile, input schema, output schema, dataset schema, changelog, and Store listing draft. Deploy with the Apify CLI after authenticating:

```bash
apify login
apify push
```

The Actor is published in Apify Store without creator monetization; normal Apify platform usage may apply. No tax/KYC or payout setup was required for publication.

### Reliability notes

- HTTP requests use a descriptive user agent, bounded timeouts, and limited retries.
- RSS is only the discovery layer; the Actor parses each official issue index and its linked records.
- Part I grouped pages are identified by their official anchors; Part II items use their individual SOR/SI pages.
- Open consultations are merged into matching Part I records by canonical URL, so a proposal appears once with its deadline attached.
- Fixture tests mirror the actual Government of Canada structures and a separate live smoke test checks the current endpoints.

### License

MIT

# Actor input Schema

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

Case-insensitive phrases matched against titles, summaries, departments, statutory authorities, registration numbers, and classification. Leave empty to include everything.

## `keywordMode` (type: `string`):

Match any keyword or require all keywords.

## `parts` (type: `array`):

Part I contains notices and proposed regulations; Part II contains enacted regulations and statutory instruments.

## `includeConsultations` (type: `boolean`):

Read the official open-consultations page and attach exact comment deadlines to proposed regulations.

## `includeNotices` (type: `boolean`):

Include government, commission, miscellaneous, and Parliament notices in addition to proposed regulations.

## `onlyNewOrChanged` (type: `boolean`):

Use persistent state to suppress unchanged records. Disable for a complete point-in-time export.

## `maxIssuesPerPart` (type: `integer`):

Number of recent RSS issues to inspect for each selected part.

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

Maximum number of matching dataset items emitted in one run.

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

Timeout for each public Government of Canada HTTP request.

## `stateStoreName` (type: `string`):

Named Apify key-value store used to detect new and changed records across runs.

## `stateKey` (type: `string`):

Record key within the named state store. Change it to start an independent monitoring stream.

## `asOf` (type: `string`):

Optional ISO 8601 timestamp used for deterministic daysRemaining calculations and tests. Normally leave empty.

## Actor input object example

```json
{
  "keywords": [],
  "keywordMode": "any",
  "parts": [
    "I",
    "II"
  ],
  "includeConsultations": true,
  "includeNotices": true,
  "onlyNewOrChanged": true,
  "maxIssuesPerPart": 1,
  "maxItems": 250,
  "requestTimeoutSecs": 30,
  "stateStoreName": "canada-gazette-regulatory-monitor-state",
  "stateKey": "STATE_V1"
}
```

# Actor output Schema

## `records` (type: `string`):

New, changed, or requested point-in-time Canada Gazette records.

## `summary` (type: `string`):

Source endpoints, counts, and run timestamp.

# 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("peterdrucker481/canada-gazette-regulatory-monitor").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("peterdrucker481/canada-gazette-regulatory-monitor").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 peterdrucker481/canada-gazette-regulatory-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,peterdrucker481/canada-gazette-regulatory-monitor"
        }
    }
}

```

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/gYadcFDSQCsmYt1ht/builds/6LyahH6KEQbTVcX7s/openapi.json
