# Matrix Public Rooms Extractor (`datamule/matrix-publicrooms-extractor`) Actor

Point at ANY Matrix homeserver and extract its public room directory over the Client-Server API. One row per room: room ID, name, topic, member count, canonical alias, avatar, join rule, room type. Opaque next\_batch pagination; optional token unlocks search/space filters.

- **URL**: https://apify.com/datamule/matrix-publicrooms-extractor.md
- **Developed by:** [Datamule](https://apify.com/datamule) (community)
- **Categories:** Developer tools, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 room records

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

## Matrix Public Rooms Extractor

Point at **any Matrix homeserver** and extract its **public room directory** — the
list of rooms that homeserver publishes to the federation — over the Matrix
Client-Server API (`GET /_matrix/client/v3/publicRooms`). One structured row per
public room, paginated through the server's own opaque `next_batch` cursor.

Works against any Matrix homeserver (Synapse, Dendrite, Conduit, …) — they all
speak the same Client-Server directory contract, so one actor reads them all:
matrix.org, matrix.tchncs.de, gnome.modular.im, mozilla.modular.im,
fedora.ems.host, and thousands more.

### What you get

One row per public room, keyed on the always-present `room_id`:

| Field | Description |
|-------|-------------|
| `room_id` | Canonical room ID (e.g. `!abc:matrix.org`) — always present |
| `name` | Room display name (nullable — many rooms are unnamed) |
| `topic` | Room topic / description (nullable) |
| `canonical_alias` | Human alias, e.g. `#community:matrix.org` (nullable) |
| `num_joined_members` | Joined member count (may be 0) |
| `avatar_url` | Room avatar `mxc://` URI (nullable) |
| `world_readable` | Whether history is world-readable |
| `guest_can_join` | Whether guests may join |
| `join_rule` | e.g. `public`, `knock`, `invite` (nullable) |
| `room_type` | e.g. `m.space` for spaces; null for regular rooms |
| `_homeserverUrl` / `_server` / `_page` / `_rowIndex` / `_totalRoomCountEstimate` | Provenance |

### Input

| Field | Required | Description |
|-------|----------|-------------|
| `homeserverUrl` | ✅ | Homeserver base URL, e.g. `https://matrix.org` |
| `server` | | Query a **different** server's directory through this homeserver (`?server=`) — usually needs a token |
| `search` | | Full-text filter over name/alias/topic — uses POST, usually needs a token |
| `roomType` | | `all` (default) · `spaces` (m.space only) · `rooms` (exclude spaces) |
| `accessToken` | | Matrix access token — unlocks search / room-type filters / federated queries |
| `maxRecords` | | Stop after N rooms (default 2000) |
| `pageSize` | | Rooms per page (default 100; server may cap lower) |

#### Anonymous vs authenticated

The **anonymous `GET` listing works on any homeserver that publishes its
directory publicly** — no token needed. The Matrix spec routes full-text
**search**, **room-type filters**, and **federated `?server=` queries** through
the `POST` endpoint, which **most homeservers gate behind an access token**
(they return `M_MISSING_TOKEN`). Supply `accessToken` to use those; leave it
empty for a plain public-directory listing.

### Example

```json
{
  "homeserverUrl": "https://matrix.org",
  "maxRecords": 100
}
````

### Use cases

- **Federation monitoring** — track which rooms a homeserver publishes over time.
- **Community discovery** — enumerate spaces and rooms across the Matrix network.
- **Moderation intelligence** — surface newly-published rooms, aliases, topics.
- **Directory research** — member-count and room-type distributions per server.

### How it works

- Anonymous `GET /_matrix/client/v3/publicRooms` by default; `POST` with a
  `filter` only when `search` / `roomType` is set.
- Opaque-cursor pagination: the response `next_batch` is echoed as the next
  request's `since`; the walk stops when the server omits it. The
  `total_room_count_estimate` is treated as a hint, never a page terminator.
- Rate limits (`M_LIMIT_EXCEEDED`) are honored via `retry_after_ms` backoff.
- Fails fast (never a fabricated empty success) if the homeserver is unreachable,
  rejects the query (auth/forbidden), or the directory matched zero rooms.

### Pricing

Pay-per-event: **$0.0005 per room record** (tiered volume discount by
subscription tier). You pay only for rooms actually emitted.

# Actor input Schema

## `homeserverUrl` (type: `string`):

Base URL of ANY Matrix homeserver (Synapse / Dendrite / Conduit / …). Its public-room directory is read via the Client-Server API GET /\_matrix/client/v3/publicRooms. Examples: https://matrix.org · https://matrix.tchncs.de · https://gnome.modular.im · https://fedora.ems.host. The anonymous GET listing works on any server that publishes its directory publicly.

## `server` (type: `string`):

Optional. Query a DIFFERENT server's published directory THROUGH the homeserver above (the ?server= parameter). NOTE: most homeservers gate remote/federated directory queries behind an access token and return M\_FORBIDDEN / M\_MISSING\_TOKEN anonymously — provide 'Access token' when using this. Leave empty to read the homeserver's own directory.

## `search` (type: `string`):

Optional full-text search over room name / alias / topic (the directory filter's generic\_search\_term). Using search switches to the POST endpoint, which most homeservers require an access token for — provide 'Access token' if the server rejects it anonymously. Leave empty to list the whole directory.

## `roomType` (type: `string`):

Filter the directory by type. 'all' = every entry (anonymous GET). 'spaces' = only m.space entries. 'rooms' = only regular rooms (exclude spaces). A type filter uses the POST endpoint, which most homeservers require an access token for.

## `accessToken` (type: `string`):

Optional Matrix access token (Bearer). Anonymous GET listing needs none, but POST search / room-type filters and federated ?server= queries are commonly auth-gated (M\_MISSING\_TOKEN) — supply a token to unlock them. Never required for a plain public-directory listing.

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

Stop after emitting this many room rows. Opaque next\_batch pagination halts early once reached. Each emitted room is billed as one record.

## `pageSize` (type: `integer`):

Rooms requested per directory page (the API 'limit'). The server may cap this below your value. Larger pages = fewer round-trips.

## `userAgent` (type: `string`):

Override the default descriptive User-Agent header. Many homeservers are volunteer / community deployments — please keep a descriptive agent.

## `timeoutSecs` (type: `integer`):

Per-request timeout in seconds for each directory-page fetch.

## Actor input object example

```json
{
  "homeserverUrl": "https://matrix.org",
  "roomType": "all",
  "maxRecords": 2000,
  "pageSize": 100,
  "timeoutSecs": 60
}
```

# Actor output Schema

## `results` (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 = {
    "homeserverUrl": "https://matrix.org"
};

// Run the Actor and wait for it to finish
const run = await client.actor("datamule/matrix-publicrooms-extractor").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 = { "homeserverUrl": "https://matrix.org" }

# Run the Actor and wait for it to finish
run = client.actor("datamule/matrix-publicrooms-extractor").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 '{
  "homeserverUrl": "https://matrix.org"
}' |
apify call datamule/matrix-publicrooms-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=datamule/matrix-publicrooms-extractor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Matrix Public Rooms Extractor",
        "description": "Point at ANY Matrix homeserver and extract its public room directory over the Client-Server API. One row per room: room ID, name, topic, member count, canonical alias, avatar, join rule, room type. Opaque next_batch pagination; optional token unlocks search/space filters.",
        "version": "0.1",
        "x-build-id": "s1qMLUzxmx255iP9P"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/datamule~matrix-publicrooms-extractor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-datamule-matrix-publicrooms-extractor",
                "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/datamule~matrix-publicrooms-extractor/runs": {
            "post": {
                "operationId": "runs-sync-datamule-matrix-publicrooms-extractor",
                "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/datamule~matrix-publicrooms-extractor/run-sync": {
            "post": {
                "operationId": "run-sync-datamule-matrix-publicrooms-extractor",
                "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",
                "required": [
                    "homeserverUrl"
                ],
                "properties": {
                    "homeserverUrl": {
                        "title": "Homeserver URL",
                        "type": "string",
                        "description": "Base URL of ANY Matrix homeserver (Synapse / Dendrite / Conduit / …). Its public-room directory is read via the Client-Server API GET /_matrix/client/v3/publicRooms. Examples: https://matrix.org · https://matrix.tchncs.de · https://gnome.modular.im · https://fedora.ems.host. The anonymous GET listing works on any server that publishes its directory publicly."
                    },
                    "server": {
                        "title": "Remote server (federated directory)",
                        "type": "string",
                        "description": "Optional. Query a DIFFERENT server's published directory THROUGH the homeserver above (the ?server= parameter). NOTE: most homeservers gate remote/federated directory queries behind an access token and return M_FORBIDDEN / M_MISSING_TOKEN anonymously — provide 'Access token' when using this. Leave empty to read the homeserver's own directory."
                    },
                    "search": {
                        "title": "Search term",
                        "type": "string",
                        "description": "Optional full-text search over room name / alias / topic (the directory filter's generic_search_term). Using search switches to the POST endpoint, which most homeservers require an access token for — provide 'Access token' if the server rejects it anonymously. Leave empty to list the whole directory."
                    },
                    "roomType": {
                        "title": "Room type filter",
                        "enum": [
                            "all",
                            "spaces",
                            "rooms"
                        ],
                        "type": "string",
                        "description": "Filter the directory by type. 'all' = every entry (anonymous GET). 'spaces' = only m.space entries. 'rooms' = only regular rooms (exclude spaces). A type filter uses the POST endpoint, which most homeservers require an access token for.",
                        "default": "all"
                    },
                    "accessToken": {
                        "title": "Access token (optional)",
                        "type": "string",
                        "description": "Optional Matrix access token (Bearer). Anonymous GET listing needs none, but POST search / room-type filters and federated ?server= queries are commonly auth-gated (M_MISSING_TOKEN) — supply a token to unlock them. Never required for a plain public-directory listing."
                    },
                    "maxRecords": {
                        "title": "Max records",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Stop after emitting this many room rows. Opaque next_batch pagination halts early once reached. Each emitted room is billed as one record.",
                        "default": 2000
                    },
                    "pageSize": {
                        "title": "Page size",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Rooms requested per directory page (the API 'limit'). The server may cap this below your value. Larger pages = fewer round-trips.",
                        "default": 100
                    },
                    "userAgent": {
                        "title": "User-Agent (optional)",
                        "type": "string",
                        "description": "Override the default descriptive User-Agent header. Many homeservers are volunteer / community deployments — please keep a descriptive agent."
                    },
                    "timeoutSecs": {
                        "title": "Request timeout (seconds)",
                        "minimum": 5,
                        "type": "integer",
                        "description": "Per-request timeout in seconds for each directory-page fetch.",
                        "default": 60
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
