NYC-Trash-Map

NYC-Trash-Map

Docker app from Forder's Repository

Overview

Interactive map of New York City trash, recycling, organics, and bulk-item collection schedules by street and day.

NYC Trash Map

🌐 Check out the live map: trashmap.nyc

Map NYC sanitation collection schedules by street. Pick a day and filter by refuse, recycling, organics, or bulk trash. The map also supports live browser location tracking. Hostable as a standalone Docker container.

Screenshot of trashmap.nyc

Production Compose

The production example matches the public deployment: one application container, Caddy-managed HTTPS, and persistent data and certificate volumes. Copy the example environment, replace map.example.com with your domain, and start it:

cp .env.production.example .env
docker compose --env-file .env -f compose.production.yaml up -d

The example always pulls ghcr.io/johnngone/nyc-trash-map:latest. Set APP_IMAGE in .env when you want to pin a release instead. DNS for DOMAIN must point to the host, and ports 80 and 443 must reach Caddy.

The first refresh downloads the source data and builds the map release. The basemap loads before that work is done. Street schedules appear after the release passes validation.

The application accepts only its current persisted-data contract. Start a new installation with an empty data directory; incompatible manifests and artifacts are deliberately rejected.

Release images are published for both linux/amd64 and linux/arm64. Docker automatically pulls the matching image for the host. Published images use the form ghcr.io/johnngone/nyc-trash-map:<release-tag>.

Standalone container

For an HTTP-only deployment behind an existing proxy, mount a persistent data directory and publish the application port directly:

HOST_PORT=8080
DATA_DIR=/opt/nyc-trash-map/data
IMAGE=ghcr.io/johnngone/nyc-trash-map:latest

mkdir -p "$DATA_DIR"
docker pull "$IMAGE"
docker run -d \
  --name nyc-trash-map \
  --restart unless-stopped \
  -p "${HOST_PORT}:8000" \
  -v "${DATA_DIR}:/app/data" \
  -e DATA_REFRESH_ON_STARTUP=true \
  "$IMAGE"

Set the APP_* variables to customize visible branding and the metadata returned in the initial HTML response. Recreate the container after changing them; the image does not need to be rebuilt. Set APP_PUBLIC_URL to the deployment's public HTTPS origin without a trailing slash. It supplies the canonical URL, social image URL, sitemap, and structured-data URL.

The initial page response includes the configured title and description, Open Graph and Twitter cards, canonical metadata, and JSON-LD. The server also exposes /robots.txt and /sitemap.xml.

APP_ROBOTS_TXT defaults to a private, crawl-blocking policy. Use literal \n sequences between lines when setting a custom value.

Private default (leaving the variable empty produces the same file):

APP_ROBOTS_TXT=User-agent: *\nDisallow: /

Public example:

APP_ROBOTS_TXT=User-agent: *\nAllow: /\nSitemap: https://map.example.com/sitemap.xml
docker run -d \
  --name nyc-trash-map \
  --restart unless-stopped \
  -p "${HOST_PORT}:8000" \
  -v "${DATA_DIR}:/app/data" \
  -e APP_TITLE="My Collection Map" \
  -e APP_SUBTITLE="Find pickup schedules in your neighborhood." \
  -e APP_BROWSER_TITLE="Collection Schedule Map | Example Organization" \
  -e APP_META_DESCRIPTION="Explore local refuse and recycling schedules by street." \
  -e APP_PUBLIC_URL="https://map.example.com" \
  -e APP_ROBOTS_TXT="User-agent: *\\nAllow: /\\nSitemap: https://map.example.com/sitemap.xml" \
  "$IMAGE"

HTTPS and location tracking

Live location tracking requires HTTPS. http://localhost also works for local use. Put a public or LAN deployment behind an HTTPS reverse proxy and allow the browser location permission.

The map starts with a citywide NYC overview centered on U Thant Island. If location access was already granted, or the user previously completed a manual locate in that browser, it automatically starts tracking and moves to the user's neighborhood. Otherwise, it waits for the location button so first-time visitors do not receive an unsolicited permission prompt. Locations outside the collection-data bounds leave the automatic startup view on the NYC overview.

The browser keeps location coordinates in memory and stores only the auto-location preference locally. The app does not send coordinates to its API or store them in the data volume. Firefox may ask again after a temporary location permission expires.

Deployment settings

The Docker image refreshes data on startup and every 14 days. Set these environment variables on docker run or in Docker Compose when you need different behavior.

Setting Default Purpose
APP_TITLE NYC Trash Map Visible and accessible map heading
APP_SUBTITLE See collection schedules by street and day. Text beneath the map title
APP_BROWSER_TITLE NYC Trash Map Browser-tab, search-result, Open Graph, and Twitter title
APP_SHORT_NAME NYC Trash Map Home-screen and installed-app label
APP_META_DESCRIPTION Explore NYC sanitation schedules by street and day. View trash, recycling, organics, and bulk collection near your live location on an interactive map. Search-result, Open Graph, and Twitter description
APP_PUBLIC_URL empty Public HTTPS origin used for canonical, Open Graph, JSON-LD, robots, and sitemap URLs
APP_ROBOTS_TXT empty (Disallow: /) Complete /robots.txt override using literal \n line separators; set an explicit allow policy to make the site crawlable
DATA_REFRESH_ON_STARTUP true Start a refresh when the container starts
DATA_REFRESH_ENABLED true Run the background refresh scheduler
DATA_REFRESH_INTERVAL_DAYS 14 Days between scheduled refreshes
DATA_REFRESH_FAILURE_RETRY_MINUTES 30 Minutes before retrying a failed refresh
DATA_RELEASE_RETENTION 2 Validated releases kept on the data volume
HEALTH_SYNC_HASH_MAX_BYTES 16777216 Artifact bytes checked during a health request before validation continues in the background
MIN_LION_SOURCE_ROWS 200000 Minimum raw LION rows required for a first release
MIN_DSNY_SOURCE_ROWS 500 Minimum DSNY polygons required for a first release
MIN_OUTPUT_FEATURES 100000 Minimum processed features required for a first release
MAX_COUNT_DROP_PERCENT 10 Maximum permitted count decline from the current release
TILE_MIN_ZOOM 11 Lowest generated vector-tile zoom
TILE_MAX_ZOOM 16 Highest generated vector-tile zoom
TILE_MAX_COMPRESSED_BYTES 1572864 Per-tile compressed-size gate; may only lower the hard ceiling
TILE_MAX_UNCOMPRESSED_BYTES 6291456 Per-tile decoded-size gate; may only lower the hard ceiling
VITE_BASEMAP_TILEJSON_URL OpenFreeMap Basemap TileJSON URL used while building the image

VITE_BASEMAP_TILEJSON_URL is a build setting. Rebuild the image after changing it. The remaining settings apply when the container starts.

For a source build with Docker Compose copy .env.example to .env. Set APP_HOST_PORT in .env then run:

docker compose up -d --build
docker compose logs -f app

Compose mounts ./data at /app/data. The container's manifest pointer is fixed at /app/data/data_manifest.json; there is no separate loose database or tileset path to configure.

Documentation

API

Endpoint Use
GET /api/health Release status record counts and artifact checks
GET /api/live Process liveness; always 200 while the server is running
GET /api/map-config Current vector tile URL and map availability
GET /api/tiles/{version}/{z}/{x}/{y}.pbf Gzip vector tiles used by the map

Before the first release is committed, /api/live and the frontend return 200, /api/health returns 503, /api/map-config returns available: false, and tile URLs return 404. The basemap remains usable while the frontend retries. After publication, health requires the committed v4 summary and database-v1 tables directly; it does not reconstruct missing release metadata or tolerate older table layouts. /api/refuse-streets and /api/app-config do not exist.

Interactive API documentation is available at /docs, /redoc, and /openapi.json in development. All three routes return 404 when APP_ENV=production.

Development keeps the complete HTTP request-access log. Production suppresses successful request lines but logs every 4xx and 5xx response, including /api/health readiness failures. Refresh progress and actionable application failures remain in the container log.

Troubleshooting

Problem Check
Basemap loads but street schedules do not Run curl http://127.0.0.1:8080/api/health and inspect docker logs nyc-trash-map
Health returns 503 while checksums are verifying Keep polling. The app checks each committed database and tileset before serving it
Location button is unavailable Use HTTPS or localhost and grant browser location permission
Docker reports that the port is allocated Change HOST_PORT such as 9090
The first refresh cannot publish data Confirm the mounted data directory is writable and inspect the container log

Local development

Install the backend dependencies and start FastAPI from the repository root.

python -m pip install -e ".[refresh]"
python -m uvicorn backend.app.main:app --reload --host 127.0.0.1 --port 8000

Start the frontend in another terminal.

cd frontend
npm ci
VITE_API_BASE_URL=http://127.0.0.1:8000 npm run dev

In PowerShell, use $env:VITE_API_BASE_URL='http://127.0.0.1:8000'; npm run dev. There is intentionally no Vite proxy; set this URL explicitly whenever the frontend and backend use different origins.

Use python scripts/run_refresh.py --allow-large-run to build a local dataset from the official sources. Run python scripts/run_refresh.py --status to inspect the current release.

License

The project code is licensed under the MIT License. Third-party data and assets retain their own terms.

This map derives street schedules from NYC Department of Sanitation frequency data and NYC Department of City Planning LION street centerlines. Use the official DSNY collection schedule lookup for an address-specific answer.

Basemap data comes from OpenMapTiles and OpenStreetMap. See third-party notices for licenses.

Install NYC-Trash-Map on Unraid in a few clicks.

Find NYC-Trash-Map in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for NYC-Trash-Map Review the template variables and paths Click Install

Requirements

The first data refresh may take some time. Live browser location requires HTTPS or localhost. New installations must begin with an empty application-data directory.

Categories

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/johnngone/nyc-trash-map:latest
Last Updated2026-09-25
First Seen2026-09-25

Runtime arguments

Web UI
http://[IP]:[PORT:8000]/
Network
bridge
Shell
bash
Privileged
false

Template configuration

App DataPathrw

Persistent generated map data. New installations must begin with an empty directory.

Target
/app/data
Default
/mnt/user/appdata/nyc-trash-map
Value
/mnt/user/appdata/nyc-trash-map
Web UI PortPorttcp

Host port used to access NYC Trash Map.

Target
8000
Default
54711
Value
54711
Application EnvironmentVariable

Runs the application in production mode.

Target
APP_ENV
Default
production
Value
production
Enable Automatic RefreshVariable

Run the automatic background data-refresh scheduler.

Target
DATA_REFRESH_ENABLED
Default
true
Value
true
Refresh on StartupVariable

Check for and process updated NYC data when the container starts.

Target
DATA_REFRESH_ON_STARTUP
Default
true
Value
true
Refresh Interval (Days)Variable

Number of days between successful automatic refresh attempts.

Target
DATA_REFRESH_INTERVAL_DAYS
Default
14
Value
14
Refresh Failure Retry (Minutes)Variable

Minutes to wait before retrying a failed data refresh.

Target
DATA_REFRESH_FAILURE_RETRY_MINUTES
Default
30
Value
30
Retained Data ReleasesVariable

Number of validated data releases retained on the persistent volume.

Target
DATA_RELEASE_RETENTION
Default
2
Value
2
Application TitleVariable

Visible and accessible heading displayed above the map.

Target
APP_TITLE
Default
NYC Trash Map
Value
NYC Trash Map
Application SubtitleVariable

Subtitle displayed below the map heading.

Target
APP_SUBTITLE
Default
See collection schedules by street and day.
Value
See collection schedules by street and day.
Browser TitleVariable

Title used for browser tabs, search results, and social previews.

Target
APP_BROWSER_TITLE
Default
NYC Trash Map
Value
NYC Trash Map
Application Short NameVariable

Short label used when the application is installed on a device.

Target
APP_SHORT_NAME
Default
NYC Trash Map
Value
NYC Trash Map
Meta DescriptionVariable

Description used by search engines and social previews.

Target
APP_META_DESCRIPTION
Default
Explore NYC sanitation schedules by street and day. View trash, recycling, organics, and bulk collection near your live location on an interactive map.
Value
Explore NYC sanitation schedules by street and day. View trash, recycling, organics, and bulk collection near your live location on an interactive map.
Public URLVariable

Public HTTPS origin without a trailing slash, such as https://example.com. Used for canonical URLs, social previews, sitemap.xml, and structured metadata.

Target
APP_PUBLIC_URL
Robots.txt PolicyVariable

Complete robots.txt contents using literal \n separators. An empty value blocks web crawlers by default.

Target
APP_ROBOTS_TXT