Skip to content

Use a CARTO API key for map tiles - #902

Merged
ngm merged 1 commit into
developfrom
carto-basemap-api-key
Sep 2, 2026
Merged

Use a CARTO API key for map tiles#902
ngm merged 1 commit into
developfrom
carto-basemap-api-key

Conversation

@edwh

@edwh edwh commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

CARTO now require an API key on their raster basemaps. Without one the tiles still load, but each is stamped API KEY REQUIRED — visible on every group, event and venue map on the site.

Approach

The key is injected at runtime via window.restarters, next to the config already passed that way, rather than compiled into the bundle. Dockerfile.fly runs npm run production against a stub .env long before the deployed environment's secrets exist, so a VITE_ variable would bake in an empty string and never see the Fly secret.

leafletTiles() appends the key when present and returns the bare URL when not, so an unconfigured environment degrades to the watermark rather than a broken map. The standalone #event-map in app.js had its own copy of the tile URL and now shares the helper.

The key is not secret in any meaningful sense — it is served to every visitor in the page — but keeping it in config keeps it out of the repo and lets it differ per environment.

Secrets

Already staged as CARTO_API_KEY on restarters, restarters-dev and restarters-yesterday (staged, so it lands with this deploy — no extra restart). FLY_PREVIEW_SECRETS has been updated so previews get it too.

Verification

  • A tile fetched with the key returns clean; without it, watermarked. A bogus key returns a byte-identical watermarked tile, confirming the ?key= parameter is read. Retina @2x works.
  • 4 new unit tests for leafletTiles(); full Jest suite (29) passes; npm run production builds.
  • Built bundle contains the runtime lookup and not the key.

CARTO now require an API key on their raster basemaps. Without one the
tiles still load, but every one of them is stamped "API KEY REQUIRED".

The key is injected into the page at runtime via window.restarters,
alongside the config already passed that way, rather than compiled into
the bundle. Dockerfile.fly runs the asset build against a stub .env long
before the deployed environment's secrets exist, so a VITE_ variable
would bake in an empty string and never see the Fly secret.

leafletTiles() appends the key when one is present and returns the bare
URL when it isn't, so an unconfigured environment degrades to the
watermark rather than to a broken map. The standalone #event-map in
app.js had its own copy of the tile URL; it now shares the helper.

The key is not secret in any meaningful sense - it is served to every
visitor in the page - but keeping it in config keeps it out of the repo
and lets it differ per environment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@edwh edwh added the preview Deploy a Fly.io preview for this PR label Sep 2, 2026
@sonarqubecloud

sonarqubecloud Bot commented Sep 2, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Preview: https://restarters-pr-902.fly.dev

✅ Ready - restore and migrations succeeded.

  • Password-protected test environment (usual dev gate password); commit 0487a2c8ec0235e4ec46cb2234c34b4aee0fb6ad merged with develop.
  • If you see a "warming up" page, give it a few minutes - it refreshes itself.
  • The preview database is refreshed on every deploy and may reset at any time; anything you create here is disposable.
  • Emails go to shared Mailpit, never to real recipients. Image uploads are disabled.
  • The app suspends when idle; the first request after a pause can take a moment.

@ngm ngm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, and works on the preview.

@ngm
ngm merged commit 21b40e3 into develop Sep 2, 2026
5 checks passed
edwh added a commit that referenced this pull request Sep 2, 2026
#902 keyed the tile URL on the Laravel side, but the client carries its
own copy in utils/mapConstants.js - annotated "no API key required",
which stopped being true - so every map in the SPA would have come back
watermarked once this branch lands.  GroupMap, EventVenueMap and
GroupForm all read it.

useLeafletTiles() appends the key from runtimeConfig.public and returns
the bare URL without one, so an unconfigured environment degrades to the
watermark rather than a broken map.  Runtime config rather than a
compiled-in constant for the same reason as the Laravel side: the image
is built long before the deployed environment's secrets exist, and
Dockerfile.fly already relies on this for apiBase ("runtime-overridable
... so no API URL is baked").

The key falls back to CARTO_API_KEY, which the machine already carries as
a Fly secret and Nitro shares the environment with, so no second secret
is needed anywhere - production, previews or FLY_PREVIEW_SECRETS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Deploy a Fly.io preview for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants