# Zalo OA Profile & Change Monitor (`produkdigitalali/zalo-oa-business-intelligence-monitor`) Actor

Extract public Zalo Official Account profile metadata and monitor profile, availability, and recovery changes over time. Supports OA URLs, numeric IDs, and custom slugs with persistent change detection and changes-only output.

- **URL**: https://apify.com/produkdigitalali/zalo-oa-business-intelligence-monitor.md
- **Developed by:** [ProdukDigitalAli](https://apify.com/produkdigitalali) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.49 / 1,000 oa profile checkeds

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

## Zalo OA Business Intelligence & Change Monitor

Extract **public Zalo Official Account landing-page data** and monitor what changes between runs. The Actor is designed for recurring brand/OA monitoring rather than private Zalo data access.

It works with logged-out public `zalo.me/{oaId}` and custom OA-slug pages. Current public pages may expose only metadata such as **name, description, canonical identity hints, and QR URL**. Richer fields such as verification, category, OA type, follower count, tier, avatar, cover, address, and working hours are returned **only when the public page actually exposes them**.

### What you get

Each public OA snapshot can include:

- OA ID and/or custom slug
- public name and description
- canonical URL
- QR image URL
- avatar / cover when separately exposed
- verification, category, OA type, tier, follower count, address, and working hours when available
- `dataLevel`: `META` or `STRUCTURED`
- `availablePublicFields` and `missingPublicFields`
- deterministic `profileHash`
- parser diagnostics that explain which public signals were actually found

The Actor deliberately treats **HTTP 200 as insufficient evidence of success**. Login walls, block pages, not-found pages, rate limits, and parse failures are classified instead of silently emitted as valid OA profiles.

### Why use this instead of a raw Zalo OA scraper?

The primary product is recurring monitoring:

- monitor public OA name and description changes
- detect verification/category/tier/follower changes when the page exposes those fields
- track address and business-hour changes when available
- detect availability transitions such as `PUBLIC -> LOGIN_REQUIRED / NOT_FOUND`
- detect `RECOVERED` when an OA becomes publicly accessible again
- maintain stable public OA directories with hashes and data-quality signals
- feed records into CRM, lead-enrichment, API, MCP, or scheduled automation workflows

### Input

Use any combination of:

- `startUrls`: public `https://zalo.me/...` OA pages
- `oaIds`: numeric OA IDs
- `slugs`: public OA slugs
- `oaText`: bulk pasted URLs / IDs / slugs

The Actor normalizes and deduplicates targets before applying `maxItems`.

#### Minimal example

```json
{
  "startUrls": [{"url": "https://zalo.me/officialaccount"}],
  "maxItems": 10,
  "monitorMode": false,
  "proxyConfiguration": {"useApifyProxy": false}
}
```

#### Monitoring example

```json
{
  "oaIds": ["4462152339089565647"],
  "monitorMode": true,
  "emitChangesOnly": true,
  "stateNamespace": "my-brand-watchlist",
  "proxyConfiguration": {"useApifyProxy": false}
}
```

### Output statuses

Snapshot rows use explicit statuses:

- `PUBLIC`
- `LOGIN_REQUIRED`
- `NOT_FOUND`
- `ACCESS_DENIED`
- `RATE_LIMITED`
- `PARSE_ERROR`
- `ERROR`
- `INVALID`

Only successfully parsed **public OA pages** trigger the custom PPE event. Invalid, blocked, login-required, not-found, rate-limited, and failed lookups are not charged by that custom event.

### Data quality

`dataLevel` makes the source quality explicit:

- `META` — the public page exposed metadata only, typically name/description/QR and identity hints.
- `STRUCTURED` — a structured OA payload was found and richer fields may be available.

`profileCompletenessScore` is a 0-100 heuristic for useful business fields. It is **not** an official Zalo score. `availablePublicFields` and `missingPublicFields` make the result auditable.

The Actor does not infer or fabricate missing verification, category, follower, address, or working-hour values.

### Monitoring behavior

When `monitorMode=true`, stable state is stored in a named Key-Value Store. The change engine can emit:

- `NEW_OA`
- `PROFILE_CHANGED`
- `VERIFICATION_CHANGED`
- `ADDRESS_CHANGED`
- `HOURS_CHANGED`
- `CATEGORY_CHANGED`
- `TIER_CHANGED`
- `FOLLOWER_COUNT_CHANGED`
- `LOGIN_REQUIRED`
- `NOT_FOUND`
- `RECOVERED`
- `UNCHANGED`

`changeTypes` can contain multiple simultaneous changes while `changeType` remains the primary event. `fieldChanges` contains previous/current values.

Transient `ACCESS_DENIED`, `RATE_LIMITED`, `PARSE_ERROR`, and network failures **do not overwrite the previous healthy baseline**.

QR image URLs are excluded from the deterministic profile-change fingerprint because Zalo may rotate QR image tokens without changing the OA business profile.

#### First run vs later runs

- First public run -> `NEW_OA` unless `baselineOnly=true`
- Same monitored profile later -> `UNCHANGED`
- Field changes -> field-level change event(s)
- Public page becomes login-required/not-found -> availability change
- It becomes public again -> `RECOVERED`
- `emitChangesOnly=true` suppresses snapshots and `UNCHANGED`, while operational errors remain visible

### Public page vs official Zalo OA API

This Actor intentionally works without a Zalo login or OA token. Zalo's official OA management API can expose richer OA-management fields but requires an authorized OA access token and the relevant permissions. This Actor does not claim those private/account-scoped API fields when they are absent from the logged-out public page.

### Access and proxy policy

The Actor uses an HTTP client with Chrome-style TLS impersonation. Direct access is the default. A proxy can be configured through Apify when legitimately needed for geography or network reliability.

The Actor is intentionally not built around CAPTCHA solving, private sessions, QR logins, or private account data. If public access becomes unavailable, it surfaces the access status rather than fabricating data.

### Pricing model

The source defines one custom PPE event:

`oa-profile-checked` — one successfully fetched and parsed public OA page.

Current source price: **$0.00249 per successful public OA check** before any synthetic Actor-start event configured at publication. Failed/blocked/non-public lookups are not charged by this custom event.

### Suggested Store task examples

1. **Monitor Zalo OA profile changes**
2. **Build a public Zalo OA directory**
3. **Track Zalo OA availability and recovery**
4. **Use Zalo OA change events from an API or AI workflow**

### Scope and privacy

Public Official Account landing pages only. The Actor does **not** collect or attempt to access:

- private chats or message history
- contacts
- group members
- private personal profiles
- logged-in OA Manager data
- private follower identities
- QR/session authentication

Zalo and related marks belong to their respective owners. This is an independent tool and is not affiliated with or endorsed by Zalo/VNG. Users are responsible for lawful use and applicable terms.

# Actor input Schema

## `startUrls` (type: `array`):

Public zalo.me Official Account URLs. Numeric OA URLs and public custom OA slugs are supported.

## `oaIds` (type: `array`):

Numeric Zalo Official Account IDs (10-24 digits).

## `slugs` (type: `array`):

Public custom path after zalo.me/, for example officialaccount.

## `oaText` (type: `string`):

Optional bulk input separated by new lines, commas, semicolons, or tabs. It is merged and deduplicated with the fields above.

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

Hard cap after normalization and deduplication.

## `monitorMode` (type: `boolean`):

Persist stable OA state and emit NEW\_OA / profile / verification / address / hours / availability / recovery changes.

## `emitChangesOnly` (type: `boolean`):

In monitor mode, suppress snapshots and UNCHANGED rows. Transient errors are still emitted so silent failures are visible.

## `baselineOnly` (type: `boolean`):

In monitor mode, save the first stable state without emitting an initial NEW\_OA / LOGIN\_REQUIRED / NOT\_FOUND change event.

## `stateNamespace` (type: `string`):

Separates independent monitor jobs using the same Actor account.

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

Public OA pages are attempted directly by default. Enable an appropriate legitimate proxy only when needed for your geography or network.

## `concurrency` (type: `integer`):

Parallel OA page checks. Keep modest values for stable recurring monitoring.

## `requestTimeoutSeconds` (type: `integer`):

Timeout for one public OA HTTP request.

## `maxRetries` (type: `integer`):

Retries transient network, rate-limit, and server errors with bounded backoff.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://zalo.me/officialaccount"
    }
  ],
  "oaIds": [
    "4462152339089565647"
  ],
  "slugs": [],
  "oaText": "",
  "maxItems": 10,
  "monitorMode": false,
  "emitChangesOnly": false,
  "baselineOnly": false,
  "stateNamespace": "default",
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "concurrency": 5,
  "requestTimeoutSeconds": 20,
  "maxRetries": 2
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "startUrls": [
        {
            "url": "https://zalo.me/officialaccount"
        }
    ],
    "oaIds": [
        "4462152339089565647"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("produkdigitalali/zalo-oa-business-intelligence-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 = {
    "startUrls": [{ "url": "https://zalo.me/officialaccount" }],
    "oaIds": ["4462152339089565647"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("produkdigitalali/zalo-oa-business-intelligence-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 '{
  "startUrls": [
    {
      "url": "https://zalo.me/officialaccount"
    }
  ],
  "oaIds": [
    "4462152339089565647"
  ],
  "maxItems": 10
}' |
apify call produkdigitalali/zalo-oa-business-intelligence-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,produkdigitalali/zalo-oa-business-intelligence-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/v8XYeBTULBJzy6o3w/builds/138yDciQ2KMXN77vb/openapi.json
