Settings Reference
The Admin -> Settings page in the GeoLens web UI groups every system setting into seven tabs. This page orients you to what each tab controls and where to find the deeper documentation. The settings UI is the recommended interface for day-to-day configuration; the same values are also stored as .env variables and can be set at deploy time.
Replace https://geolens.example.com with your GeoLens instance’s URL in every example below.
General
Section titled “General”The General tab covers the instance’s public URLs, the announcement banner, publishing and editing policy, and logging. Most of it is operational defaults, but two settings are not cosmetic: the public URLs are what the OAuth callback builds its post-login redirect from, and Enable Dataset Editing decides whether data can be edited in place.
| Setting | Purpose |
|---|---|
| Public App URL / Public API URL | public_app_url, public_api_url: the externally reachable origins GeoLens builds absolute links, OGC self-links, and OAuth redirects from. The OAuth callback resolves them from explicit configuration rather than a forwarded host header, so it fails closed (500) when they are unset. public_base_url is a deprecated alias for public_api_url — it still resolves, but logs a startup warning |
| Privacy Policy URL | privacy_url: shown as a link on the login and register pages; leave empty to hide the link |
| Require Metadata for Publishing | require_metadata_for_publish (default: false). Datasets must carry complete metadata before they can be published |
| Enable Dataset Editing | enable_dataset_editing (default: false). Allows geometry drawing and attribute editing on dataset detail pages |
| Log Level / JSON Logging | log_level, log_json: runtime log verbosity and structured-log output |
| Site banner | banner_enabled, banner_text, banner_color: a site-wide announcement banner shown to every visitor (logged-in and anonymous) when enabled with non-empty text; pick a color (info, success, warning, or destructive — warning is the default and the fallback for an unrecognized value). Any https:// URL in the text renders as a link that opens in a new tab; wrap it in angle brackets (<https://...>) to have the URL taken verbatim, including trailing punctuation. Banner text is escaped, so markup in it is never rendered, and text over 2,000 characters renders as plain text with no linking. Visitors can dismiss it for the rest of their browser session |
These map to environment variables documented under Configuration Reference -> General. Persistent settings stored in the database take precedence over .env defaults.
The Map tab controls which basemaps the instance offers, the default view for new maps, and which map-builder plugins are available. Existing maps keep their per-map settings; this tab only seeds the defaults shown when a user creates a fresh map.
| Setting | Purpose |
|---|---|
| Basemaps | basemaps: the list offered to map authors. Four presets ship enabled — OpenFreeMap Positron, OpenFreeMap Dark, OpenStreetMap, and OpenFreeMap Bright — and each can be switched off individually. Custom entries take a name, a URL — an XYZ/TMS tile template, a MapLibre GL style JSON URL, or (since 1.16) a PMTiles archive, either as a bare https:// URL ending in .pmtiles or the same URL pmtiles://-prefixed — attribution, and an optional API key interpolated server-side into an {api_key} placeholder. A raster PMTiles archive renders directly as a basemap. A bare vector archive is rejected when you add it — it carries no styling information — so reference a vector archive from a style JSON URL instead; the form reads the archive’s header before saving to tell the two apart |
| Default map center | map_defaults.center_lat / map_defaults.center_lng (default: 20, 0) |
| Default zoom level | map_defaults.zoom (default: 2). Zoom 0 to 22; typical values 2 to 4 for global views, 10 to 14 for city scale |
| Enabled plugins | enabled_plugins: which map-builder plugins are available |
The basemap list is configurable: you can add MapTiler, Mapbox, or self-hosted basemap servers. Configuration details are in Configuration Reference.
The Auth tab covers password policy, JWT expiry, registration, and OAuth providers. The OAuth Providers section is the entry point for the OAuth/OIDC setup walkthrough.
| Setting | Maps to |
|---|---|
| JWT signing secret | JWT_SECRET_KEY (env-only, not editable in UI) |
| Access token lifetime | ACCESS_TOKEN_EXPIRE_MINUTES (default: 15) |
| Refresh token lifetime | REFRESH_TOKEN_EXPIRE_DAYS (default: 7) |
| Self-registration | REGISTRATION_ENABLED (default: false); see User management |
| Require Email Verification | email_verification_required (admin setting, not read from .env; default: true). Self-registered accounts must confirm their email before first login; delivery requires a configured SMTP channel (see Configuration Reference -> Outbound notifications) |
| Login-as-Landing Page | LANDING_FIRST (default: false). Redirects unauthenticated visits to / to the login page instead of the catalog |
| Password Login Enabled | password_login_enabled (default: true). When off, POST /auth/login returns 403 for every user without manage_settings; admins keep password login as a break-glass path |
| Login rate limit | login_rate_limit (admin setting, not read from .env; default: 5 attempts/min). Applies to POST /auth/login per client IP |
| Allowed Email Domains | allowed_email_domains (default: empty = any domain). Enforced on sign-up, login, SSO, and admin-create. When the list is non-empty, a first-time SSO identity must present a verified email in an allowed domain or the login is refused; a returning user is checked against their stored address when the IdP claim is unverified, and a returning user with manage_settings keeps the same break-glass exemption |
| OAuth providers | Database-stored; see OAuth/OIDC setup |
JWT_SECRET_KEY is set in .env and not editable through the UI. Rotating it invalidates all active JWT tokens (forcing every user to log in again) and makes every stored OAuth client secret undecryptable — the encryption key is derived from this secret, so nothing is re-encrypted for you. After rotating, re-enter each provider’s client secret in the admin UI before anyone tries to sign in with SSO.
Storage
Section titled “Storage”The Storage tab controls upload limits, per-user quotas, and how long rendered tiles stay cached. Where files physically live is environment-only: STORAGE_PROVIDER and the S3_* / AZURE_* credentials are read from the environment and are not editable here — see Configuration Reference -> Storage provider.
| Setting | Maps to |
|---|---|
| Upload max size | UPLOAD_MAX_SIZE_MB (default: 500) |
| Allowed extensions | UPLOAD_ALLOWED_EXTENSIONS |
| Tile Cache TTL | TILE_CACHE_TTL (seconds; default: 300) |
| Max Storage per User | max_storage_bytes_per_user (admin setting, not read from .env; default: 0 = unlimited) |
| Max Datasets per User | max_datasets_per_user (admin setting, not read from .env; default: 0 = unlimited) |
Backup off-site replication uses the same S3 credentials by default. See Backups & restore for BACKUP_S3_ENABLED and the dedicated backup destination configuration. Storage and backups can use different buckets if needed by setting backup-specific overrides.
Network
Section titled “Network”The Network tab covers CORS origins, the API rate limits, and the OGC API Features page-size ceiling.
| Setting | Maps to |
|---|---|
| CORS origins | CORS_ALLOWED_ORIGINS: comma-separated list of frontend origins allowed to make credentialed or native-route calls to the API |
| Global rate limit | global_rate_limit (admin setting; default 60 requests/second) |
| Semantic search rate limit | semantic_search_rate_limit (admin setting; default 30 requests/min) |
| Basemap proxy rate limit | basemap_proxy_rate_limit (admin setting; default 120 requests/min) |
| OGC Features max page size | ogc_items_max_page_size (admin setting, not read from .env; default 1000). Ceiling for limit on /api/collections/{id}/items; a larger limit is clamped silently |
The login rate limit lives on the Auth tab (login_rate_limit, default 5 attempts/min), not here.
Every rate limit on this tab is counted in a store shared by the whole deployment when REDIS_URL is set, and once per API worker when it is not. The OGC Features page-size ceiling is not a rate limit and is unaffected. Without the store, a saved value of 60 requests/second is enforced as 60 per worker, and the bundled production compose file runs two API workers by default. Each worker logs rate_limit_storage_not_configured at startup when the variable is unset. See Configuration.
CORS_ALLOWED_ORIGINS defaults to empty. That does not mean no cross-origin browser access: anonymous requests to the standards paths (/api/, /api/conformance, /api/collections*, /api/stac*, the DCAT routes) and to the vector and raster tile routes always get a credential-free Access-Control-Allow-Origin: *, so a public page on any origin can read the public catalog and draw public tiles with no setup. Since 1.14.1 the anonymous catalog search routes (/api/search/datasets/, /api/search/facets/) get the same credential-free wildcard, with a preflight that advertises only the GET they answer, so a cross-origin page can query native search directly. Saved searches (/api/search/saved/) stay authenticated and get no wildcard. Both public policies also expose Retry-After, so a cross-origin caller can read the retry window on a 429.
The setting governs everything else: any request that carries a credential (X-Api-Key, Authorization, cookies) and every native application route. Those get credentialed CORS responses (Access-Control-Allow-Credentials: true), and the browser spec forbids pairing that with a wildcard, so the middleware rejects * and you must list exact origins (comma-separated). Set them explicitly for any browser client served from a different origin than the API that signs in or sends a key.
Outbound notification channels (SMTP email and webhooks for signup, ingest, and health events) are environment-only — their credentials are secrets and never stored in the settings database, so they do not appear in this tab. See Configuration Reference -> Outbound notifications.
The AI tab toggles AI chat across GeoLens — the map builder panel, the dataset-detail Ask AI assistant, and the read-only map viewer — and configures the upstream LLM provider. The AI feature toggle ships enabled, but AI is inert until a provider API key is configured — with no key, AI endpoints return unavailable.
| Setting | Maps to |
|---|---|
| LLM Provider | llm_provider (admin setting, not read from .env). Selects which provider serves inference: Anthropic or OpenAI-compatible |
| Anthropic API key | ANTHROPIC_API_KEY (environment-only; the tab shows a configured / not-set indicator, not an input) |
| LLM Model | llm_model (admin setting). The tab has a single model input, whichever provider is selected; its initial value comes from LLM_MODEL (default: claude-sonnet-5) when an Anthropic key is set and from OPENAI_MODEL (default: gpt-4o) otherwise |
| Light LLM Model | llm_model_light: the cheaper model used for the AI’s SQL generation and metadata suggestions, not for chat. The tab has no input for it — set it with PUT /api/settings/, or seed the default from OPENAI_MODEL_LIGHT. Falls back to claude-haiku-4-5-20251001 when an Anthropic key is set and to the configured OpenAI-compatible model otherwise |
| Max AI Tokens per User per Day | max_ai_tokens_per_user_per_day (admin setting, not read from .env; default: 0 = unlimited) |
| OpenAI-compatible API key | OPENAI_API_KEY (environment-only; the tab shows a configured / not-set indicator, not an input) |
| OpenAI-compatible base URL | OPENAI_BASE_URL: for non-OpenAI endpoints (Azure, local servers) |
| AI feature toggle | ai_enabled (admin setting, not read from .env; default: true). When off, the AI chat panel is hidden for all users |
| Send Sample Values | ai_send_sample_values (admin setting, default: true). Includes sample column values from the dataset in the prompt sent to the provider; turn it off to send column names and types only |
| Semantic Search | semantic_search_enabled (admin setting, not read from .env; default: false) |
| Embedding Model | EMBEDDING_MODEL (default: text-embedding-3-small); the OpenAI-compatible model that generates search vectors |
| Embedding Base URL | EMBEDDING_BASE_URL: a separate endpoint for embedding generation; falls back to OPENAI_BASE_URL when empty |
| Embedding Dimensions | EMBEDDING_DIMS (default: 1536); Detect probes the configured model rather than making you look the number up |
The provider is an explicit setting, not an inference from which key happens to be present. llm_provider defaults to Anthropic when ANTHROPIC_API_KEY is set and to the OpenAI-compatible path (OPENAI_API_KEY + OPENAI_BASE_URL) otherwise, but an admin can change it on this tab at any time. Whichever provider is selected must have its own key configured — readiness is checked against the selected provider only, so a key for the other one does not make AI available.
Provider API keys are the one AI setting the UI cannot change: set them in .env and restart. Everything else on this tab is admin-editable at runtime.
The AI chat is gated by both the use_ai_chat permission (see User management) and the global feature toggle. Disabling the toggle takes effect immediately for all sessions; users see the AI panel disappear on next page load.
Enabling semantic search
Section titled “Enabling semantic search”Semantic search lives in the Semantic Search & Embeddings section of the AI tab. Turning the toggle on is only one of three steps, and it is the one that does the least on its own: with the toggle on and no embeddings generated, search silently falls back to keyword-only results.
-
Configure an OpenAI-compatible API key. Embeddings always go through the OpenAI-compatible path (
OPENAI_API_KEY, optionally withOPENAI_BASE_URLfor Azure, Ollama, or a local server) — an Anthropic key drives chat but cannot generate embeddings. Set Embedding Model to the model you want vectors from, then click Detect next to Embedding Dimensions to probe the model for its output size instead of entering it by hand. The button stays disabled until an OpenAI-compatible key is configured. -
Turn on the Semantic Search toggle. This is
semantic_search_enabled, an admin setting stored in the database and not read from.env. PuttingSEMANTIC_SEARCH_ENABLEDin your.envfile has no effect. -
Generate the embeddings. The Embedding Coverage panel shows how many catalog records currently have a vector (
embedded_records/total_records). Click Generate Missing Embeddings to embed the records that lack one. Coverage has to be non-zero before semantic ranking changes any result.
Embeddings for new and edited records are generated as they are saved, so the backfill is a one-time catch-up for the catalog you already have. Use Regenerate All after changing the embedding model or dimensions: existing vectors were produced by the old model and are not comparable to new ones.
Since 1.19.0 the coverage panel also reports the runs themselves, so you can watch a backfill instead of inferring it from the coverage figure:
- A run in flight shows its progress. The panel reads out records embedded against the run’s total, refreshed as it goes. A run that has not finished selecting its records has no total yet, and the readout says it is starting rather than showing a count.
- The last five finished runs are listed, newest first, each with how it ended (complete, failed or cancelled), the records it embedded, the records it could not embed where the run recorded a count, and when it finished. A finished run with a non-zero failure count left coverage gaps.
- An estimate appears before you start one. Each button that applies is costed in whole minutes, taken from the throughput of the most recent completed run, so the figure describes this deployment’s own provider rather than a generic rate. There is no estimate until one run has completed, and it gives way to the progress readout while a run is in flight.
- Both buttons are disabled while any run is in flight, including one another operator started. The run slot is shared, not per admin session, and reopening the page mid-run shows you the run in progress.
The same three steps are available over the API: POST /api/settings/detect-embedding-dims/ probes the model, PUT /api/settings/ writes semantic_search_enabled, and GET /api/admin/embedding-stats/ plus POST /api/admin/backfill-embeddings/ report coverage and run the backfill (add ?force=true for the regenerate-all behavior). The stats response carries current_run, recent_runs and estimate alongside the coverage counts, which is what the panel above renders. See Search & Discovery for what changes on the user-facing side once it is on.
Permissions
Section titled “Permissions”The Permissions tab is where the role-to-capability matrix is overridden. The default matrix is documented at User management -> Roles & permissions; this tab lets you grant additional capabilities to non-admin roles or restrict capabilities further.
Common customizations:
- Restricted viewer: remove
exportfrom theviewerrole for read-only audit-trail use cases - Metadata-only editors: remove
uploadandcreate_layersfromeditorso the role can curate metadata without adding data - Locked-down public: disable
use_ai_chatfor all non-admin roles to control LLM API spend
The matrix covers the three built-in roles (viewer, editor, admin). Creating additional roles is not supported.
Custom permission matrices persist in the database as a single role_permissions setting and survive restarts. To reset to the shipped defaults, use Reset to Defaults on the Permissions tab itself — it restores the built-in role/capability matrix.
See also
Section titled “See also”- User management & RBAC: the Permissions tab interacts with the role/permission matrix
- OAuth/OIDC setup: the Auth tab includes OAuth provider configuration
- Backups & restore: the Storage tab + backup-specific config (
BACKUP_S3_ENABLED) - Configuration reference: per-environment-variable deep documentation