# Mobile Deep Link Association Monitor (`defenestrator/mobile-deep-link-association-monitor`) Actor

Monitor public Apple AASA and Android assetlinks files for mobile universal-link/app-link association drift.

- **URL**: https://apify.com/defenestrator/mobile-deep-link-association-monitor.md
- **Developed by:** [Defenestrator](https://apify.com/defenestrator) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 monitor rows

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 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.

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

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## Mobile Deep Link Association Monitor

Monitor public Apple Universal Links and Android App Links association files for release, growth, and security regressions.

This Actor checks each public domain for:

- Apple `apple-app-site-association` files at `/.well-known/apple-app-site-association` and `/apple-app-site-association`.
- Android Digital Asset Links files at `/.well-known/assetlinks.json`.
- JSON parseability, HTTP status, redirects, content-type signals, association counts, app IDs, package names, signing certificate fingerprints, path rules, Android 15 dynamic rules, and semantic drift against a previous run snapshot.

It is designed for scheduled monitoring. Run it once to capture a baseline, then paste `OUTPUT.snapshot` into the next run or scheduled task to alert on changed app IDs, package names, certificate fingerprints, path rules, dynamic rules, broken files, or missing expected associations.

### Why teams run it repeatedly

Universal Links and App Links can silently break after web deploys, CDN changes, app ID/package changes, certificate rotations, marketing-domain migrations, or mobile-release changes. A normal website uptime monitor can say the domain is up while iOS or Android link verification is broken. This Actor produces decision-ready rows for mobile QA, growth, lifecycle marketing, and app-security teams.

### Input

- `targets`: public domains or URLs. URLs are accepted, but only their public host is used.
- `platforms`: `ios`, `android`, or both.
- `targetExpectations`: optional JSON keyed by domain, for example:

```json
{
  "www.example.com": {
    "iosAppIds": ["TEAMID.com.example.app"],
    "androidPackageNames": ["com.example.app"],
    "androidSha256Fingerprints": ["AA:BB:CC:..."]
  }
}
````

- `previousSnapshot` or `previousSnapshotJson`: copy from a prior run's `OUTPUT.snapshot` to enable drift alerts. Malformed, incomplete, or duplicate-key snapshot rows fail the run instead of silently disabling comparison.
- `includeAllRows`: keep true for complete baseline exports. When false, only alert/error rows are written and `OUTPUT.snapshot` intentionally contains only those billed rows, so it is not a complete next-run baseline.

### Output rows

Each dataset row represents one target domain and platform file. Important fields include:

- `domain`, `platform`, `fileType`, `finalUrl`, `statusCode`, `redirectCount`.
- `iosAppIds`, `androidPackageNames`, `androidSha256Fingerprints`, `relationNames`.
- `pathRuleCount`, `componentsRuleCount`, `dynamicRuleCount`.
- `changedSincePrevious`, `changedFields`, `missingExpected`, `semanticHash`.
- `alert`, `priority`, `riskScore`, `alertReasons`, `recommendedAction`.

`OUTPUT.snapshot` contains compact rows suitable for the next run's `previousSnapshot` input.

### Safety and limitations

- Only public HTTP(S) destinations are supported. Localhost, private, link-local, multicast, documentation, and other reserved IP destinations are blocked; each request and redirect connects only to the exact public addresses validated for that hop.
- The Actor does not log in, use a browser, call App Store / Play Console APIs, or verify app entitlements/manifests. It validates public website association files only.
- Apple and Google are trademarks of their respective owners. This Actor is unofficial and is not affiliated with Apple, Google, Android, or any monitored domain.
- Do not submit private, internal, confidential, or VPN-only hostnames.

### Pricing

**Buyer-unit price: $2.00 per 1,000 domain/platform association rows written to the default dataset**, plus the `$0.00005` run-start event.

This Actor uses Apify Pay Per Event (PPE) pricing:

- `apify-actor-start`: `$0.00005` per run start.
- `apify-default-dataset-item`: `$0.002` per dataset row (`Monitor row`).
- Platform usage is included in the event price; users do not pay a separate platform-usage pass-through.
- A dataset row is exactly one emitted domain/platform result. With `includeAllRows=false`, clean non-alert checks are not emitted or item-charged.
- The Actor checks the PPE charge result, stops before further source work when the dataset-item charge limit is reached, and reports intended versus actually written rows.

Use Apify's max total charge setting before starting a run if you want a hard spend cap.

# Actor input Schema

## `targets` (type: `array`):

Public web domains to check. URLs are accepted, but only their public host is used. Private/internal/localhost/reserved destinations are blocked.

## `platforms` (type: `array`):

Supported values: ios, android. Leave both enabled for full mobile deep-link association monitoring.

## `targetExpectations` (type: `object`):

Optional JSON object keyed by domain. Each value may include iosAppIds, androidPackageNames, and androidSha256Fingerprints arrays. Missing expected values create alerts.

## `watchIosAppIds` (type: `array`):

Optional global iOS appID values such as TEAMID.com.example.app. Every supplied value is required and each missing value is reported.

## `watchAndroidPackageNames` (type: `array`):

Optional global Android package names such as com.example.app. Every supplied value is required and each missing value is reported.

## `previousSnapshot` (type: `object`):

Optional snapshot object copied from a previous run's OUTPUT.snapshot. Used for semantic drift comparison.

## `previousSnapshotJson` (type: `string`):

Optional JSON text version of a previous OUTPUT.snapshot for API callers or Console users who prefer text paste.

## `includeAllRows` (type: `boolean`):

If false, only alert/error rows are pushed to the dataset. OUTPUT always contains the full summary and snapshot.

## `alertOnFirstRun` (type: `boolean`):

If true, valid first-run rows get a low-priority baseline alert. Keep false for quiet scheduled monitoring after initial setup.

## `requireHttps` (type: `boolean`):

Standards require HTTPS. Leave enabled except for deliberate local testing; private/internal URLs are still blocked.

## `maxTargets` (type: `integer`):

Safety cap for domains checked in one run.

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

Timeout for each association-file request.

## `maxResponseBytes` (type: `integer`):

Maximum bytes accepted for each association file. Apple documents a 128 KB uncompressed AASA limit; this default allows some real-world headroom while bounding cost.

## Actor input object example

```json
{
  "targets": [
    "www.airbnb.com",
    "www.spotify.com",
    "www.nytimes.com"
  ],
  "platforms": [
    "ios",
    "android"
  ],
  "targetExpectations": {},
  "watchIosAppIds": [],
  "watchAndroidPackageNames": [],
  "previousSnapshot": {},
  "previousSnapshotJson": "",
  "includeAllRows": true,
  "alertOnFirstRun": false,
  "requireHttps": true,
  "maxTargets": 50,
  "requestTimeoutSecs": 20,
  "maxResponseBytes": 262144
}
```

# Actor output Schema

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

Dataset rows: one checked platform association file per target unless includeAllRows=false.

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

Run-level summary plus OUTPUT.snapshot for scheduled semantic drift comparison.

# 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 = {
    "targets": [
        "www.airbnb.com",
        "www.spotify.com",
        "www.nytimes.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("defenestrator/mobile-deep-link-association-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 = { "targets": [
        "www.airbnb.com",
        "www.spotify.com",
        "www.nytimes.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("defenestrator/mobile-deep-link-association-monitor").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 '{
  "targets": [
    "www.airbnb.com",
    "www.spotify.com",
    "www.nytimes.com"
  ]
}' |
apify call defenestrator/mobile-deep-link-association-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=defenestrator/mobile-deep-link-association-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Mobile Deep Link Association Monitor",
        "description": "Monitor public Apple AASA and Android assetlinks files for mobile universal-link/app-link association drift.",
        "version": "0.0",
        "x-build-id": "jdZIawdZf3am8a9M9"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/defenestrator~mobile-deep-link-association-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-defenestrator-mobile-deep-link-association-monitor",
                "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/defenestrator~mobile-deep-link-association-monitor/runs": {
            "post": {
                "operationId": "runs-sync-defenestrator-mobile-deep-link-association-monitor",
                "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/defenestrator~mobile-deep-link-association-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-defenestrator-mobile-deep-link-association-monitor",
                "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": {
                    "targets": {
                        "title": "Public domains or URLs",
                        "minItems": 1,
                        "maxItems": 250,
                        "type": "array",
                        "description": "Public web domains to check. URLs are accepted, but only their public host is used. Private/internal/localhost/reserved destinations are blocked.",
                        "items": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 2048
                        },
                        "default": [
                            "www.airbnb.com",
                            "www.spotify.com",
                            "www.nytimes.com"
                        ]
                    },
                    "platforms": {
                        "title": "Platforms to check",
                        "minItems": 1,
                        "maxItems": 2,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Supported values: ios, android. Leave both enabled for full mobile deep-link association monitoring.",
                        "items": {
                            "type": "string",
                            "pattern": "^(ios|android)$"
                        },
                        "default": [
                            "ios",
                            "android"
                        ]
                    },
                    "targetExpectations": {
                        "title": "Per-domain expected associations",
                        "type": "object",
                        "description": "Optional JSON object keyed by domain. Each value may include iosAppIds, androidPackageNames, and androidSha256Fingerprints arrays. Missing expected values create alerts.",
                        "default": {},
                        "additionalProperties": true
                    },
                    "watchIosAppIds": {
                        "title": "Global iOS appIDs to watch",
                        "type": "array",
                        "description": "Optional global iOS appID values such as TEAMID.com.example.app. Every supplied value is required and each missing value is reported.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "watchAndroidPackageNames": {
                        "title": "Global Android packages to watch",
                        "type": "array",
                        "description": "Optional global Android package names such as com.example.app. Every supplied value is required and each missing value is reported.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "previousSnapshot": {
                        "title": "Previous OUTPUT.snapshot object",
                        "type": "object",
                        "description": "Optional snapshot object copied from a previous run's OUTPUT.snapshot. Used for semantic drift comparison.",
                        "default": {}
                    },
                    "previousSnapshotJson": {
                        "title": "Previous snapshot JSON text",
                        "maxLength": 2000000,
                        "type": "string",
                        "description": "Optional JSON text version of a previous OUTPUT.snapshot for API callers or Console users who prefer text paste.",
                        "default": ""
                    },
                    "includeAllRows": {
                        "title": "Include all checked rows",
                        "type": "boolean",
                        "description": "If false, only alert/error rows are pushed to the dataset. OUTPUT always contains the full summary and snapshot.",
                        "default": true
                    },
                    "alertOnFirstRun": {
                        "title": "Alert on first-run baselines",
                        "type": "boolean",
                        "description": "If true, valid first-run rows get a low-priority baseline alert. Keep false for quiet scheduled monitoring after initial setup.",
                        "default": false
                    },
                    "requireHttps": {
                        "title": "Require HTTPS",
                        "type": "boolean",
                        "description": "Standards require HTTPS. Leave enabled except for deliberate local testing; private/internal URLs are still blocked.",
                        "default": true
                    },
                    "maxTargets": {
                        "title": "Maximum targets per run",
                        "minimum": 1,
                        "maximum": 250,
                        "type": "integer",
                        "description": "Safety cap for domains checked in one run.",
                        "default": 50
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout seconds",
                        "minimum": 5,
                        "maximum": 120,
                        "type": "integer",
                        "description": "Timeout for each association-file request.",
                        "default": 20
                    },
                    "maxResponseBytes": {
                        "title": "Maximum response bytes",
                        "minimum": 4096,
                        "maximum": 1048576,
                        "type": "integer",
                        "description": "Maximum bytes accepted for each association file. Apple documents a 128 KB uncompressed AASA limit; this default allows some real-world headroom while bounding cost.",
                        "default": 262144
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
