# District Seat Availability Scraper (`monknwarriors/district-seat-availability-scraper`) Actor

Reads the live seat map for a District (district.in) movie showtime — every seat's row, number, price class and whether it's booked — and an occupancy summary per showtime.

- **URL**: https://apify.com/monknwarriors/district-seat-availability-scraper.md
- **Developed by:** [Monk N Warriors](https://apify.com/monknwarriors) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 seat map reads

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

## District Cinema Seat Availability & Occupancy Scraper

Read the **live seat map** for a District (district.in) movie showtime —
every seat's row, number, seating class, and whether it's free — plus an
occupancy summary for the whole showtime.

Built to pair with the **District Movie Showtimes & Cinema Schedule
Scraper**: it puts a ready-made `seat_layout_ref` on every showtime row —
paste that column in here.

***

### What you can do with it

- Measure **true occupancy** of a showtime, seat by seat, not just a rough count.
- Track how a show **fills up** over hours or days by re-running on the same showtimes.
- See **which rows / classes sell first** (front vs back, recliner vs classic).
- Spot **block bookings** and seating patterns.
- Locate a screen's **wheelchair-accessible seats**.

***

### Input

| Field | Description |
|---|---|
| **Showtimes** | The showtimes to read. Paste the `seat_layout_ref` values — or whole rows — from the **District Movie Showtimes Scraper**'s output. Up to 200 per run. |
| **Level of detail** | One grain per run: *Seat by seat* (default), *Occupancy by price class*, or *Occupancy summary*. |
| **Retries per showtime** / **Pause between showtimes** | Reliability knobs (defaults 2 and 1.5s). |
| **Proxy** | Residential, India by default — District only serves Indian IPs. |

Minimal input:

```json
{
  "showtimes": [
    {
      "cinemaId": 1023314, "sessionId": "20668", "providerId": 1707,
      "moviecode": "OB7YWB", "movieFormatCode": "n5N_fTqZr8", "contentId": "181196",
      "cityKey": "mumbai", "sessionDate": "2026-09-08", "screenFormat": "2D"
    }
  ]
}
```

***

### Output

The dataset is **flat** — no nested columns — so it opens cleanly in Excel /
Google Sheets. **Pick one grain with the *Level of detail* input; the whole
dataset is that grain, so every column has data** (no empty columns to
scroll past):

- **`SEAT_MAP`** (default) — one row per physical seat: its class, price,
  row, number and status.
- **`OCCUPANCY_BY_CLASS`** — one row per seating class per showtime:
  occupied / available per class.
- **`OCCUPANCY_SUMMARY`** — one row per showtime: whole-screen occupancy.

Every row carries the movie / cinema / showtime identity — `session_key`,
`movie_title`, …, `cinema_address`, `latitude`, `longitude`, `screen_name`,
`show_datetime_ist` — read straight from District's response, so they're
filled even for a bare pipe-string reference. Each showtime's occupancy
also lands in the run's `RUN_REPORT`.

#### Two availability numbers — read this

District exposes seat availability two ways and they don't always agree:

- the **seat-selection layout** — the grid its booking page renders and you
  click seats on. This scraper reads it: `seat_status` / `seat_is_open` per
  seat, tallied into `seats_open` / `area_seats_open` / `class_seats_open`.
- District's own **availability badge** — the "N seats available" figure on
  the showtime list. Carried as the `district_*` columns
  (`district_seats_available`, `district_class_available`, …).

For most cinemas they match. For **PVR / INOX**, District marks the layout
*representational* (`layout_is_representational = true`) — the arrangement
may not match the auditorium and the two counts can differ by a handful of
seats. Both are in every row so you can compare and pick whichever your own
spot-check of district.in agrees with.

#### `SEAT_MAP` grain — one row per seat

```json
{
  "row_type": "SEAT",
  "session_key": "district|mumbai|225612|1023314|20693|2026-09-09",
  "movie_title": "Hanuman Ansh",
  "cinema_name": "MovieMax Andheri (E), Mumbai",
  "show_datetime_ist": "2026-09-09T05:50:00+05:30",

  "area_code": "MR", "area_label": "PRIME PLUS ROWS",
  "area_price": 99.0, "area_currency": "INR",
  "phys_row": "N",
  "seat_number": "17",
  "seat_status": "0",
  "seat_kind": "standard",
  "seat_is_open": true,
  "seat_is_taken": false,
  "is_accessible": false,
  "class_seats_open": 40, "class_seats_total": 44,
  "district_class_available": 40, "district_class_total": 44,
  "layout_is_representational": true
}
```

| Field | Meaning |
|---|---|
| `area_code` / `area_label` | Seating class, e.g. `CLASSIC ROWS`, `PRIME ROWS`, `RECLIINER ROWS`. |
| `area_price` / `area_currency` | The price of *this seat's* ticket. |
| `phys_row` / `seat_number` | The seat's row label and number. |
| `seat_status` | District's raw code from the seat layout (see table). |
| `seat_kind` | `standard`, `occupied`, `wheelchair`, `wheelchair_companion`, `accessible`, `unknown`. |
| `seat_is_open` / `seat_is_taken` | Open (selectable) / taken in District's seat layout. |
| `is_accessible` | Wheelchair / companion seat. |
| `class_seats_open` / `class_seats_total` | This seat's class, tallied from the layout. |
| `district_class_available` / `district_class_total` | District's own count for the class — compare with `class_seats_open`. |
| `layout_is_representational` | `true` for PVR / INOX (layout approximate — see above). |

**Seat status values** (from District's `messages` map):

| `seat_status` | Meaning |
|---|---|
| `0` | Open in the layout |
| `1` | Taken in the layout |
| `1000` | Wheelchair-reserved seat — bookable |
| `1001` | Wheelchair companion seat — bookable |
| `1002` | Accessibility seat — bookable |

#### `OCCUPANCY_BY_CLASS` grain — one row per class per showtime

```json
{
  "row_type": "AREA",
  "session_key": "district|mumbai|181196|1023314|20668|2026-09-08",
  "area_code": "QR", "area_label": "PRIME ROWS",
  "area_price": 300.0,
  "area_currency": "INR",
  "area_in_seat_grid": true,
  "area_seats_total": 206,
  "area_seats_taken": 184,
  "area_seats_open": 22,
  "area_occupancy_pct": 89.32,
  "area_status_color": "Y",
  "district_seats_available": 79, "district_seats_total": 206,
  "layout_is_representational": true
}
```

| Field | Meaning |
|---|---|
| `area_code` / `area_label` | The seating class. |
| `area_price` / `area_currency` | Its ticket price. |
| `area_in_seat_grid` | `false` for a class District priced but didn't return per-seat (PVR "PICTURE PERFECT") — the grid columns are then blank; `district_*` kept. |
| `area_seats_total` / `_taken` / `_open` / `_accessible` | Tallied from District's seat layout. |
| `area_occupancy_pct` | `taken / total` for the class, from the layout. |
| `area_status_color` | That class's own fill indicator (`G` / `Y` / `R` / `D`). |
| `district_seats_available` / `district_seats_total` | District's own count for the class — compare with the grid columns. |

#### `OCCUPANCY_SUMMARY` grain — one row per showtime

```json
{
  "row_type": "SUMMARY",
  "session_key": "district|mumbai|181196|1023314|20668|2026-09-08",
  "screen_name": "SCREEN 3",
  "seats_total": 330,
  "seats_taken": 271,
  "seats_open": 59,
  "seats_accessible": 2,
  "occupancy_pct": 82.12,
  "full_seats_total": 358,
  "class_count": 5,
  "classes_missing_from_grid": "PICTURE PERFECT",
  "layout_is_representational": false,
  "district_seats_total": 358,
  "district_seats_available": 128,
  "district_occupancy_pct": 64.25
}
```

| Field | Meaning |
|---|---|
| `seats_total` | Seats in District's returned layout (`full_seats_total` reconciles any missing class). |
| `seats_taken` / `seats_open` | Taken / open in the layout. `seats_open` includes bookable accessibility seats. |
| `seats_accessible` | Wheelchair + companion seats. |
| `occupancy_pct` | `seats_taken / seats_total`, from the layout. |
| `full_seats_total` | Screen capacity — `seats_total` plus any class missing from the map. Matches the capacity District states. |
| `class_count` | Number of `AREA` rows for this showtime. |
| `classes_missing_from_grid` | Comma-separated names of classes District priced but didn't return per-seat. Empty string when none. |
| `district_seats_total` / `district_seats_available` / `district_occupancy_pct` | District's own screen badge — compare with the layout counts above. |
| `screen_name` | Auditorium label. |

Also written to the run's key-value store: **`RUN_REPORT`** — every
showtime requested, whether it succeeded, its seat count and occupancy, and
the reason for any failure.

#### Views

- **Overview** — the run's grain, key columns only (the Console hides the columns that don't apply).

***

### Known limitation: PVR premium tiers

For **PVR** cinemas, the "PICTURE PERFECT" centre-block class is not
included in the seat map District returns. It still appears as an `AREA` row
(`area_in_seat_grid = false`, class and size known, per-seat availability
not) and is named in the `SUMMARY` row's `classes_missing_from_grid`. Every
other seat on the screen is covered — typically ~90%+. Non-PVR chains (INOX,
Cinepolis, MovieMax, Citylight, City Gold, …) return the full map.

***

### Notes

- A showtime whose booking window has already closed is reported as a
  failure in `RUN_REPORT` and is **not charged**.
- Seat data is live at the moment of capture — re-run to track fill-up.
- **India only.** Keep the proxy on Residential / India.

***

### Pairs with

**District Movie Showtimes & Cinema Schedule Scraper** — its output has a
`seat_layout_ref` column ready to paste straight into this Actor's input.

# Actor input Schema

## `showtimes` (type: `array`):

The showtimes to read seat maps for. Paste the `seat_layout_ref` column straight from the District Movie Showtimes & Cinema Schedule Scraper's output — each value is a ready-to-use reference. You can also paste whole rows from that scraper (the reference is picked out automatically). Up to 200 per run. Leave this empty to run a one-showtime demo on whatever's currently showing.

## `outputMode` (type: `string`):

Pick one grain — the whole dataset is that grain, so every column has data (no empty columns to scroll past). "Seat by seat": one row per seat, with its class, price, row, number and status. "Occupancy by price class": one row per seating class per showtime (occupied / available per class). "Occupancy summary": one row per showtime (whole-screen occupancy). Whichever you pick, every showtime's occupancy also lands in the run's RUN\_REPORT.

## `sessionRetries` (type: `integer`):

Extra attempts if reading a showtime's seat map fails the first time.

## `sessionDelay` (type: `number`):

A short cooldown between showtimes to stay under rate limits.

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

Leave this on the default (Residential, India) — District expects requests from an Indian IP address and blocks ones that don't. This actor fetches only small JSON responses, so proxy usage stays low.

## Actor input object example

```json
{
  "showtimes": [],
  "outputMode": "SEAT_MAP",
  "sessionRetries": 2,
  "sessionDelay": 1.5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  }
}
```

# Actor output Schema

## `seats` (type: `string`):

The default dataset. In "Seat by seat" mode: one row per seat (row\_type SEAT) plus one occupancy row per showtime (row\_type SUMMARY). In "Occupancy summary only" mode: just the SUMMARY rows.

## `seatsCsv` (type: `string`):

The same data as a spreadsheet-friendly CSV file.

## `runReport` (type: `string`):

Which showtimes were read, their seat counts and occupancy, and any that failed.

# 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 = {
    "showtimes": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("monknwarriors/district-seat-availability-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "showtimes": [] }

# Run the Actor and wait for it to finish
run = client.actor("monknwarriors/district-seat-availability-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "showtimes": []
}' |
apify call monknwarriors/district-seat-availability-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,monknwarriors/district-seat-availability-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/b6d6hkvErPm9ZMaf4/builds/np3pTzM8nSzNAfQDd/openapi.json
