Skip to content
getgeolens.com

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.

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.

SettingPurpose
Public App URL / Public API URLpublic_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 URLprivacy_url: shown as a link on the login and register pages; leave empty to hide the link
Require Metadata for Publishingrequire_metadata_for_publish (default: false). Datasets must carry complete metadata before they can be published
Enable Dataset Editingenable_dataset_editing (default: false). Allows geometry drawing and attribute editing on dataset detail pages
Log Level / JSON Logginglog_level, log_json: runtime log verbosity and structured-log output
Site bannerbanner_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 destructivewarning 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.

SettingPurpose
Basemapsbasemaps: 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 centermap_defaults.center_lat / map_defaults.center_lng (default: 20, 0)
Default zoom levelmap_defaults.zoom (default: 2). Zoom 0 to 22; typical values 2 to 4 for global views, 10 to 14 for city scale
Enabled pluginsenabled_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.

SettingMaps to
JWT signing secretJWT_SECRET_KEY (env-only, not editable in UI)
Access token lifetimeACCESS_TOKEN_EXPIRE_MINUTES (default: 15)
Refresh token lifetimeREFRESH_TOKEN_EXPIRE_DAYS (default: 7)
Self-registrationREGISTRATION_ENABLED (default: false); see User management
Require Email Verificationemail_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 PageLANDING_FIRST (default: false). Redirects unauthenticated visits to / to the login page instead of the catalog
Password Login Enabledpassword_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 limitlogin_rate_limit (admin setting, not read from .env; default: 5 attempts/min). Applies to POST /auth/login per client IP
Allowed Email Domainsallowed_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 providersDatabase-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.

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.

SettingMaps to
Upload max sizeUPLOAD_MAX_SIZE_MB (default: 500)
Allowed extensionsUPLOAD_ALLOWED_EXTENSIONS
Tile Cache TTLTILE_CACHE_TTL (seconds; default: 300)
Max Storage per Usermax_storage_bytes_per_user (admin setting, not read from .env; default: 0 = unlimited)
Max Datasets per Usermax_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.

The Network tab covers CORS origins, the API rate limits, and the OGC API Features page-size ceiling.

SettingMaps to
CORS originsCORS_ALLOWED_ORIGINS: comma-separated list of frontend origins allowed to make credentialed or native-route calls to the API
Global rate limitglobal_rate_limit (admin setting; default 60 requests/second)
Semantic search rate limitsemantic_search_rate_limit (admin setting; default 30 requests/min)
Basemap proxy rate limitbasemap_proxy_rate_limit (admin setting; default 120 requests/min)
OGC Features max page sizeogc_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.

SettingMaps to
LLM Providerllm_provider (admin setting, not read from .env). Selects which provider serves inference: Anthropic or OpenAI-compatible
Anthropic API keyANTHROPIC_API_KEY (environment-only; the tab shows a configured / not-set indicator, not an input)
LLM Modelllm_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 Modelllm_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 Daymax_ai_tokens_per_user_per_day (admin setting, not read from .env; default: 0 = unlimited)
OpenAI-compatible API keyOPENAI_API_KEY (environment-only; the tab shows a configured / not-set indicator, not an input)
OpenAI-compatible base URLOPENAI_BASE_URL: for non-OpenAI endpoints (Azure, local servers)
AI feature toggleai_enabled (admin setting, not read from .env; default: true). When off, the AI chat panel is hidden for all users
Send Sample Valuesai_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 Searchsemantic_search_enabled (admin setting, not read from .env; default: false)
Embedding ModelEMBEDDING_MODEL (default: text-embedding-3-small); the OpenAI-compatible model that generates search vectors
Embedding Base URLEMBEDDING_BASE_URL: a separate endpoint for embedding generation; falls back to OPENAI_BASE_URL when empty
Embedding DimensionsEMBEDDING_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.

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.

  1. Configure an OpenAI-compatible API key. Embeddings always go through the OpenAI-compatible path (OPENAI_API_KEY, optionally with OPENAI_BASE_URL for 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.

  2. Turn on the Semantic Search toggle. This is semantic_search_enabled, an admin setting stored in the database and not read from .env. Putting SEMANTIC_SEARCH_ENABLED in your .env file has no effect.

  3. 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.

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 export from the viewer role for read-only audit-trail use cases
  • Metadata-only editors: remove upload and create_layers from editor so the role can curate metadata without adding data
  • Locked-down public: disable use_ai_chat for 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.