# Stadia Maps Documentation Stadia Maps APIs provide a variety of geospatial functionality including routing, forward and reverse geocoding, place search, and time (zone and current) information. SDKs are available for many popular programming languages to make the data APIs easier to use. Stadia Maps also offers map solutions in the form of vector tiles (for smoother client-side rendering), raster tiles (easier on the client, but scale-dependent), and static map images which show an area and optional overlays. Most APIs are available via a free tier, but some require a paid subscription. Refer to https://stadiamaps.com/pricing for current prices. This file contains links to the most popular sections of the Stadia Maps developer documentation. # General Info # Authentication This page covers everything you need to know to access map tiles and APIs from Stadia Maps. ## Choosing the right authentication method | Use case | Recommended method | | --- | --- | | Local development (`localhost`) | No authentication needed | | Production websites | [Domain-based authentication](#domain-based-authentication) | | Mobile apps (iOS, Android) | [API key](#api-keys) | | Server-side applications | [API key](#api-keys) | | Desktop applications | [API key](#api-keys) | | Intranet websites | [API key](#api-keys) | For production websites, domain-based authentication is the most secure option. It requires no code changes and prevents API key exposure. For everything else, use an API key and follow our [security best practices](../guides/securing-your-integration/). ## Local development We've tried to make things as easy as possible for local web development. As long as you're running via a development server accessed via `localhost` or `127.0.0.1`, you don't need an API key! So your React, Vue, and even local WordPress installations will "just work" out of the box. Local development rate limits Requests made this way are subject to strict rate limits. If you start receiving HTTP 429 responses regularly, sign up for an account (it's free!) and create an [API key](#api-keys). ## Domain-based authentication Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). 1. Click "Manage Properties." 1. Under "Authentication Configuration," click the button to add your domain. Domain-based authentication works by validating the `Origin` and `Referer` headers that browsers automatically send with every request. These headers are set by the browser itself, not by JavaScript or your application code, making this method both secure and convenient for web applications. Getting a 401 Unauthorized response or seeing a Stamen warning tile? Domain authentication usually "just works" but sometimes it doesn't. These are a few common issues related to domain authentication. - [`Referrer-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) is set to `no-referrer`. Some platforms, such as Azure Static Web Apps, do this by default. Relaxing this header to something like `strict-origin-when-cross-origin` (if your site uses HTTPS; `origin-when-cross-origin` if using HTTP) will let us authenticate your requests while preserving privacy. - Are you using a hosting service like Vercel, Netlify, or GitHub pages with a custom domain? In many configurations, the headers will indicate that the request is coming from a subdomain on your host rather than your custom domain. Check the `Origin` and `Referer` headers in your browser's web inspector/dev tools to verify. - Is your page hosted on a subdomain? It's easy to forget to include the subdomain or (if appropriate) allow all subdomains. If your site is hosted on `a.b.example.com`, you need to set the subdomain to `a` and the domain to `b.example.com` as shown in the screenshot below: ## API keys To access maps and APIs outside a web browser, including server-side code and mobile apps, you need an API key. ### Generating and revoking API keys You can manage your API keys in the client dashboard. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). (If you don't have an account yet, sign up for free; no credit card required!) 1. Click "Manage Properties." 1. If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page. 1. Under "Authentication Configuration," you can generate, view or revoke your API key. #### Video: How to generate your API key ### Using your API key You can authenticate your requests by adding an API key to the query string or HTTP header. The simplest is to add a query string parameter `api_key=YOUR-API-KEY` to your request URL. For example, to access the `/tz/lookup` API endpoint, your request URL might look like this. Example URL with an API key placeholder ``` https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY ``` You can also use an `Authorization` HTTP header instead of a query string as shown below. Don't forget the `Stadia-Auth` prefix! Example Authorization header with an API key placeholder ``` Authorization: Stadia-Auth YOUR-API-KEY ``` Vector stylesheets If you're accessing vector tiles via API key (ex: in a mobile app) and you're using one of our styles, add an API key query parameter to the stylesheet URL. We'll rewrite the stylesheet so that all data sources requiring authentication use your key. This is the easiest way to get access to vector tiles in a mobile app or intranet website. If you're using your own style with our data, see our [custom style guide](../custom-styles/) for tips on authenticating our data sources. ### Protecting your API keys You should take care not to expose your API key unnecessarily. That's why we recommend domain-based authentication for web browser applications. We recommend only using API keys in cases where it is not likely to be leaked to an end user (ex: server-side and mobile applications). If you are developing locally and exceed the rate limit for keyless access, be careful not to accidentally commit your API key to your repository. Securing your API keys in apps Securing your API keys requires special care whenever an application is available to end users outside your organization. This is always tricky and tends to be a bit different for every app, but we can offer some general best practices: 1. Avoid shipping API keys in an app binary when possible. For example, on iOS you can take advantage of on-demand resources to separate this from the IPA download. 1. Ensure that any long-term storage of API keys uses the platform's hardware-secured APIs (ex: Keychain or Android Keystore). 1. Rotate your API keys periodically. You can do this manually in the dashboard, or programmatically via our [Account Management API](../client-api/) if you have access. 1. Monitor your usage in the client dashboard and investigate any unexpected spikes. For more detailed guidance, see our [Securing Your Integration](../guides/securing-your-integration/) guide. ## Next steps - [Securing Your Integration](../guides/securing-your-integration/) — Best practices for mobile apps, server-side applications, and understanding our security model - [Service Limits](../limits/) — Rate limits and usage tiers - [Account Management API](../client-api/) — Programmatic management of properties, domains, and API keys # EU Endpoints Our [commitment to privacy](https://stadiamaps.com/private-location-apis-maps/) has been a foundational value from very beginning, and we take extreme care to ensure the privacy of our customers and users. While we are confident that our privacy practices and procedures satisfy GDPR requirements by default, we recognize that some customers prefer to guarantee that all network requests be handled by servers within the European Union. To accommodate this preference, we offer EU-only endpoints for our maps and APIs. These endpoints ensure users always connect to EU-based servers. Our systems scrub PII at the network's edge, so any requests that must be ultimately handled by internal services in other regions are managed in a completely private manner. ## Using the EU Endpoints Info By utilizing EU endpoints, you will establish connections exclusively with two of our servers strategically positioned in the European Union: Frankfurt, Germany and Paris, France. To use the EU endpoints, substitute the endpoints in our documentation as shown below. ### Map Endpoints For map tiles and services, replace: ``` https://tiles.stadiamaps.com ``` with ``` https://tiles-eu.stadiamaps.com ``` Example: Using EU Endpoints for MapLibre & Alidade Smooth ``` Vector Map Demo
``` 1. This line is the key change; note the `tiles-eu` host. ### API Endpoints For routing, geocoding, time zone, and other services, replace: ``` https://api.stadiamaps.com ``` with ``` https://api-eu.stadiamaps.com ``` #### Example Code Here are some code examples of using the EU endpoints with our official SDKs and cURL. Installation Instructions The Stadia Maps JavaScript/TypeScript SDK is available for any package manager that supports the npm registry. ``` npm install @stadiamaps/api ``` ``` yarn add @stadiamaps/api ``` ``` bun add @stadiamaps/api ``` ``` import { GeospatialApi, Configuration{{ extra_js_imports }} } from '@stadiamaps/api'; // If you are writing for a backend application or can't use domain-based auth, // then you'll need to add your API key like so: // // const config = new Configuration({ basePath: "https://api-eu.stadiamaps.com", apiKey: "YOUR-API-KEY" }); (1) const config = new Configuration({ basePath: "https://api-eu.stadiamaps.com" }); const api = new GeospatialApi(config); const res = await api.tzLookup({ lat: 40.71278, lng: -74.00611 }); ``` 1. Learn how to get an API key in our [authentication guide](../authentication/). Installation Instructions The Stadia Maps Python SDK is available through any package manager that supports PyPi. ``` pip install stadiamaps ``` ``` uv add stadiamaps ``` ``` poetry add stadiamaps ``` ``` import os import stadiamaps from stadiamaps.rest import ApiException configuration = stadiamaps.Configuration(host="https://api-eu.stadiamaps.com") # Configure API key authentication (ex: via environment variable). (1) configuration.api_key['ApiKeyAuth'] = os.environ["API_KEY"] with stadiamaps.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = stadiamaps.GeospatialApi(api_client) try: res = api_instance.tz_lookup(40.71278, -74.00611) except ApiException as e: # Add your error handling here print("Exception when calling the Stadia Maps API: %s\n" % e) ``` 1. Learn how to get an API key in our [authentication guide](../authentication/). Installation Instructions If aren't already using Maven Central, add the repository in your Gradle build script. ``` repositories { mavenCentral() } ``` Then, add the API package and its dependencies. build.gradle.kts ``` dependencies { val retrofitVersion = "2.12.0" // API package implementation("com.stadiamaps:api:7.1.0") // Dependencies implementation("com.squareup.moshi:moshi-kotlin:1.15.2") implementation("com.squareup.moshi:moshi-adapters:1.15.2") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") implementation("com.squareup.retrofit2:retrofit:$retrofitVersion") implementation("com.squareup.retrofit2:converter-moshi:$retrofitVersion") implementation("com.squareup.retrofit2:converter-scalars:$retrofitVersion") } ``` build.gradle ``` dependencies { def retrofitVersion = "2.12.0" // API package implementation 'com.stadiamaps:api:7.1.0' // Dependencies implementation 'com.squareup.moshi:moshi-kotlin:1.15.2' implementation 'com.squareup.moshi:moshi-adapters:1.15.2' implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0' implementation "com.squareup.retrofit2:retrofit:${retrofitVersion}" implementation "com.squareup.retrofit2:converter-moshi:${retrofitVersion}" implementation "com.squareup.retrofit2:converter-scalars:${retrofitVersion}" } ``` Our API package is available on Maven Central. All you need to do is add a few dependencies to your `pom.xml`. pom.xml ``` 2.12.0 com.stadiamaps api 7.1.0 com.squareup.moshi moshi-kotlin 1.15.2 com.squareup.moshi moshi-adapters 1.15.2 com.squareup.okhttp3 logging-interceptor 4.12.0 com.squareup.retrofit2 retrofit ${retrofit.version} com.squareup.retrofit2 converter-moshi ${retrofit.version} com.squareup.retrofit2 converter-scalars ${retrofit.version} ``` ``` // Imports (at the top of your source file; we've used some wildcard imports for simplicity) import com.stadiamaps.api.* import com.stadiamaps.api.auth.ApiKeyAuth import com.stadiamaps.api.infrastructure.* import com.stadiamaps.api.models.* // Set your API key (from an environment variable in this case) (1) val apiKey = System.getenv("STADIA_API_KEY") ?: throw RuntimeException("API Key not set") val client = ApiClient(baseUrl = "https://api-eu.stadiamaps.com") client.addAuthorization("ApiKeyAuth", ApiKeyAuth("query", "api_key", apiKey)) // Configure a service for the group of APIs we want to talk to val service = client.createService(GeospatialApi::class.java) // Set up the request. // Note: this code is blocking for demonstration purposes. // If you're using Kotlin with coroutines, // you can also use these asynchronously within suspend functions. // Synchronous code can enqueue a callback to avoid blocking // (you'll definitely want to do one of these instead when on the main thread of an app). // See the docs for details: https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html val res = service.tzLookup(40.71278, -74.00611).execute() if (res.isSuccessful) { println("Found result: ${res.body()}") } else { println("Request failed with error code ${res.code()}") } ``` 1. Learn how to get an API key in our [authentication guide](../authentication/). Installation Instructions Our Swift SDK is distributed using the Swift Package Manager (SPM). Apple's [documentation](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) shows how to add a Swift Package dependency to your Xcode project. On the Add Package screen, you can find our package by its repository URL: `https://github.com/stadiamaps/stadiamaps-api-swift`. ``` import StadiaMaps // This setup code can go anywhere before you actually make an API call (typically in your app init) func setupStadiaMapsAPI() { // Set your API key (1) StadiaMapsAPI.customHeaders = ["Authorization": "Stadia-Auth YOUR-API-KEY"] // Configure the client to use our EU endpoint StadiaMapsAPI.basePath = "https://api-eu.stadiamaps.com" } // This function demonstrates how to call the Stadia Maps API. // If you have not yet adopted async/await in your Swift codebase, you can use the Task API // to call async functions in a non-async context: https://developer.apple.com/documentation/swift/task. func myFunction() async throws { let res = try await GeospatialAPI.tzLookup(lat: 40.71278, lng: -74.00611) // Do something with the response... print(res) } ``` 1. Learn how to get an API key in our [authentication guide](../authentication/). Installation Instructions **Composer** To install the package via [Composer](https://getcomposer.org/), add `stadiamaps/api` to your `composer.json`: ``` { "require": { "stadiamaps/api": "5.*" } } ``` Then run `composer install`. **Manual Installation** You can also download the files manually and include `autoload.php` in your scripts: ``` setApiKey('api_key', getenv('API_KEY'))->setHost('https://api-eu.stadiamaps.com'); $apiInstance = new OpenAPI\Client\Api\GeocodingApi( new GuzzleHttp\Client(), $config ); try { $result = $apiInstance->tzLookup(40.71278, -74.00611); // Do something with the response... print_r($result); } catch (Exception $e) { // Add your error handling here echo 'Exception when calling the Stadia Maps API: ', $e->getMessage(), PHP_EOL; } ``` 1. Learn how to get an API key in our [authentication guide](../authentication/). ``` curl "https://api-eu.stadiamaps.com/tz/lookup/v1?lat=40.71278&lng=-74.00611&api_key=YOUR-API-KEY" ``` # Service Limits ## Which APIs can I access? Your Stadia Maps account gives access to a subset of APIs based on your selected plan. If you try to access an API which you do not have access to, you will receive a `403 Forbidden` response. Throughout our documentation, we clarify when a feature is not available on all plans using a grid like the one below (indicating that the free tier cannot access a feature): Free Starter Standard Professional A full list of features included with each plan is available on our [pricing page](https://stadiamaps.com/pricing/). ## Who can use the free tier? Our free tier is available for development, evaluation, and non-commercial use (including academic use). Other uses require a paid subscription. See our [FAQ](https://stadiamaps.com/faqs/#acceptable-use) for more details on what uses are deemed to be commercial. You can [upgrade your free subscription](../upgrading-subscription/) to a [paid plan](https://stadiamaps.com/pricing/) at any time. ## How do I know if I am going to run out of credits? By default, our system will automatically send an email and show an alert in the [Dashboard](https://client.stadiamaps.com/dashboard/#/overview) when you have exhausted 80% of your credits and are about to be hard limited. To receive these important alerts, please use an email which you check regularly. ## What happens when I run out of credits? After you use all of your credits for a billing period (calendar month for free accounts), our default action is to hard limit until the start of the next billing cycle or plan upgrade (all APIs will respond with HTTP 429 Rate Limit Exceeded). This protects you from unexpected bills. If you want to keep serving requests beyond your selected plan's limit, you can enable additional usage in the [change plan](https://client.stadiamaps.com/dashboard/account/change-plan) section of the Dashboard. This is an opt-in, pay-as-you-go billing option with straightforward pricing on the additional credits. See our [pricing page](https://stadiamaps.com/pricing/) for details. ## How can I add additional alerts based on my credit usage? You can setup additional alerts as a percentage of credits used based on your plan's included monthly allotment in the [subscription management](https://client.stadiamaps.com/dashboard/account/subscription-details/) section of the Dashboard. ## What are your rate limits? We reserve the right to impose rate limits on customers who are abusive or disruptive of service. [Contact enterprise sales](mailto:entsales@stadiamaps.com) to discuss higher volume usage. We also enforce rate limits on [local development](../authentication/#local-development) to prevent abuse. While we do not publish exact limits for local development, it should be usable without issue for most applications. After the limit is exceeded, you will receive HTTP 429 responses for a while. Access via a registered domain or API key is not subject to the same restrictions. If you expect to be sending requests at a high rate or want to ensure your use case won't be a problem, [send us an email](mailto:support@stadiamaps.com) and our ops team will coordinate with you to ensure smooth service. Proxying and Bulk Downloading Note that proxying and bulk downloading/caching (with few exceptions) are prohibited by our [general terms of service](https://stadiamaps.com/terms-of-service). Unless you have an enterprise agreement which allows this, such behavior will typically result in escalating de-prioritization of requests and ultimately a rate limit. ## What limits are there on API call complexity? We impose the complexity limits on certain APIs. If you have a more demanding use case, [send us a message](mailto:support@stadiamaps.com), and we can discuss your use case. We're happy to discuss higher limits for enterprise customers. ### Standard Routing The following complexity limits apply to standard routing requests. | Routing profile/mode of travel | Max locations per route | Max b-line distance between all locations | | --- | --- | --- | | Automobile, bus, truck, taxi, and motorcycle | 50 | 5000 kilometers | | Bicycle, bikeshare, and motor scooter | 50 | 500 kilometers | | Low speed vehicle and pedestrian | 50 | 250 kilometers | ### Optimized Routing The following limits apply to optimized routing requests. | Routing profile/mode of travel | Max locations per route | Max b-line distance between all locations | | --- | --- | --- | | Automobile, bus, truck, and taxi | 50 | 400 kilometers | | All others | 50 | 200 kilometers | ### Time/Distance Matrix We limit time/distance matrix complexity on two dimensions: the number of matrix elements and the straight-line distance between all locations. Matrix elements are a simple multiplication of the dimensions of the input. For example, a request with 3 sources (origins) and 5 targets (destinations) has 3 x 5 = 15 elements. The size limits depend on your plan. | Routing profile/mode of travel | Max elements (Standard) | Max elements (Professional) | Max b-line distance between all locations | | --- | --- | --- | --- | | Automobile, bus, truck, and taxi | 625 | 10,000 | 400 kilometers | | All others | 625 | 10,000 | 200 kilometers | ### Bulk Geocoding Bulk geocoding requests may contain up to 5,000 queries. # Upgrading Your Stadia Maps Subscription We know that everyone's location needs are different depending on the project. At Stadia Maps, this is why we offer several options and subscription levels, from free all the way to [custom enterprise plans](mailto:entsales@stadiamaps.com). By default, when you sign up, you are given a 14-day trial of our Professional tier. After the trial, if nothing is done, your account is converted to our Free level. If you need more features or credits, or are using our services for [commercial purposes](https://stadiamaps.com/faqs#acceptable-use), you will need to upgrade to one of our paid plans. All of our plan details (credits, features, pricing, and credit schedule) are available on our [pricing page](https://stadiamaps.com/pricing). If you're unsure which plan is best suited for your needs, please [reach out](mailto:support@stadiamaps.com?subject=Help%20with%20choosing%20a%20plan). We are happy to help. Once you have determined which plan suites your needs and are ready to upgrade, you will need to enter your payment details. ## Adding Payment Information The first step to upgrading is making sure you have a current, valid payment method associated with your account. If one already exists, you can skip to the [Selecting a New Plan](#selecting-a-new-plan) section. To add or update your payment method, you will need to head on over to the [*Add Payment Method*](https://client.stadiamaps.com/dashboard/account/add-payment/) section of the *Dashboard*. You can also select *Your Account Details* from the menu, and then click *Update Payment Method* as shown below. Enter your payment method details, review the information, and once everything is correct, click *Add Payment Method*. And that's it! With your payment information entered, you can now select a new plan. ## Selecting a New Plan With a payment method associated with your account, you are now ready to choose your plan. Hop on over to the [*Change Plan*](https://client.stadiamaps.com/dashboard/#/account/change-plan) section of your account to make your selection. You can also click *Manage Subscription* from the *Dashboard* and go straight to *Change Plan*. We offer three commercial plans: *Starter*, *Standard*, and *Professional*. Each provides their own specific API access, included credits, and additional usage prices. A short summary of each is provided in this section. Identify the plan you want and click *Select* at the bottom. Help selecting a plan If you need help picking your plan, you can review our [pricing page](https://stadiamaps.com/pricing/) for additional details or [write us a note](mailto:support@stadiamaps.com?subject=Help%20with%20upgrading%20my%20account) and we will be happy to assist you. ### Additional Usage Each plan has an amount of included credits issued every month. By default *Additional Usage* is disabled and your requests will be hard limited once your account hits the plan's credit limit. Don't worry though, you will receive emails as you approach this threshold. If you think you may require more credits and would like to prevent your account from being hard limited, enable *Additional Usage*. You will automatically be billed on your next invoice for the credits used at the specified rate. Make changes at any time You can also enable and disable *Additional Usage* at any time to suit your needs. After you have made your decision, review your selections, and then click *Preview Changes*. ### Preview Changes A comparison of your current plan and the selected plan will be displayed. Please verify you are making the desired update and click *Confirm changes*. Once confirmed, your credit card will be billed immediately (and every month thereafter) until a change is made. If you are updating from one paid plan to another, the changes will be prorated. See our [billing FAQ](https://stadiamaps.com/faqs/#billing) for more details or [reach out](mailto:support@stadiamaps.com?subject=Proration%20question) to us. ### Upgrading Immediately During Your Trial If you are currently in a Free trial, you have access to all features of your currently selected plan (the Professional level by default), but have a reduced credit limit. If you need to upgrade your trial to a paid account immediately, follow the steps above to [enter your billing information](#adding-payment-information) and [plan selection](#selecting-a-new-plan). Once completed, you will see a new *Upgrade Now* button on your [*Dashboard*](https://client.stadiamaps.com/dashboard/#/overview). Clicking this will immediately charge your card on file and convert your account into an active subscription for the selected plan. ## Getting Help If you experience any issues or have questions, please [reach out](mailto:support@stadiamaps.com?subject=Help%20with%20upgrading%20my%20account). We are happy to help. # Map Styling # Custom Map Styling Want to change the look and feel of the map? Custom styles allow you to change the color scheme of an existing style, [change the language of place labels](../tutorials/changing-the-map-label-language/), and more. ## Vector Maps One major benefit to vector map tiles is that you can change the style to suit your liking (even dynamically!). Our vector tiles are compatible with the popular [OpenMapTiles schema](https://openmaptiles.org/schema/), and these base layers can be styled to fit a wide range of use cases. [MapLibre styles](https://maplibre.org/maplibre-style-spec/) are the most common method of styling vector tiles. Other renderers such as [OpenLayers](../vector/#openlayers) and [Tangram](../vector/#tangram) have their own styling tools as well, but we'll only cover GL JSON styles here as they are the most widely used. You can use these styles on the web via [MapLibre GL JS](../tutorials/vector-maps-with-maplibre-gl-js/), and on mobile via either [MapLibre Native](../native-multiplatform/maplibre-gl-native/) or [Flutter MapLibre GL](../native-multiplatform/flutter-maplibre-gl/). ### Modifying an Existing MapLibre Style Tip You are generally free to modify [Stadia Maps Styles](../themes/) for your own applications. For specific details per-style, check out our [attribution page](https://stadiamaps.com/attribution/). We recommend using [Maputnik](https://maplibre.org/maputnik), an open-source style editor, to create and edit MapLibre styles. You can get started modifying one of our styles in three easy steps: 1. Select "Open" from the Maputnik menu bar. 1. Enter the JSON URL for one of our [styles](../themes/). 1. Customize it to your liking! Once you're happy with the result, save the modified style using the "Export" button in the top menu. If you'll be accessing our map tiles via API key (ex: in a mobile app), be sure to enter your API key in the export dialog. Maputnik will do the rest! ### Hosting or Bundling your Custom Style Once you're happy with the result, you'll need to host the style somewhere: either on the web (your server, CDN, etc.) or bundled with your app. Then, rather than loading one of our styles via URL, load your own! Now all you have to do is load your custom style (URL or embedded JSON) instead of ours! (If you don't already have a map in your website or app, check out our documentation on maps for [web](../maps-for-web/) or [mobile, desktop & multi-platform apps](../native-multiplatform/overview/)). ### Advanced: Starting from Scratch or Porting from Another Vendor If you're migrating from another vendor, the first thing you'll need to know is what schema their vector tiles follow. For OpenMapTiles-based sources, many things will "just work" (though even within OMT, there are a lot of variations and custom layers). For less easy cases, you will need to figure out how to map between their schema and the [OpenMapTiles schema](https://openmaptiles.org/schema/) on your own. In addition to vector and satellite imagery layers, we also offer global elevation and other datasets. You can find these on our [additional data tilesets](../tilesets/) page, along with documentation and URLs for access. Here is a minimal skeleton on which to build your own style, pre-filled with the URLs for our OpenMapTiles-compatible source, sprites (you can substitute `alidade_smooth` for any of our [map styles](../themes/)), and glyphs (fonts). Tip If you are not using [domain-based auth](../authentication/#domain-based-authentication) (ex: for a mobile app), you will need to add an API key to the OpenMapTiles URL query string: `https://tiles.stadiamaps.com/data/openmaptiles.json?api_key=YOUR-API-KEY` If you need to always use EU servers for regulatory reasons, change the host to `tiles-eu.stadiamaps.com`. See [EU Endpoints](../eu-gdpr-endpoints/) for more info. Skeletal MapLibre Style JSON Starter ``` { "sources": { "openmaptiles": { "type": "vector", "url": "https://tiles.stadiamaps.com/data/openmaptiles.json", "attribution": "© Stadia Maps © OpenMapTiles © OpenStreetMap" } }, "sprite": "https://tiles.stadiamaps.com/styles/alidade-smooth/sprite", "glyphs": "https://tiles.stadiamaps.com/fonts/{fontstack}/{range}.pbf", "layers": [...] } ``` ### Advanced: Customizing Sprites You can generate your own sprite files using [Spreet](https://github.com/flother/spreet), and host them on your server/CDN. Then, add them to your JSON style (using the `sprite` key). Note that (as in the example JSON above) you should *not* include the suffix or extension in the URL. For example, if your output base name is `sprite`, you would use `https://my-domain.com/path/to/sprite` in your JSON style. MapLibre will automatically request `https://my-domain.com/path/to/sprite.json` and `https://my-domain.com/path/to/sprite@2x.png` respectively (`@2x` is appended automatically for retina/HiDPI displays). ### Advanced: Customizing Fonts In our own themes, we have rolled up our default font into a "super-font" stack with the fallback order we want. This makes map styles easier to edit. Stadia font families - Stadia Regular - Stadia Italic - Stadia Bold - Stadia Semibold If you want to change the fallback order or remove specific fonts, you can mix and match from the full list below (collapsed). Full individual font list - Noto Sans Arabic Light - Noto Sans Arabic Medium - Noto Sans Arabic Regular - Noto Sans Armenian Light - Noto Sans Armenian Medium - Noto Sans Armenian Regular - Noto Sans Ethiopic Light - Noto Sans Ethiopic Medium - Noto Sans Ethiopic Regular - Noto Sans Georgian Light - Noto Sans Georgian Medium - Noto Sans Georgian Regular - Noto Sans Hebrew Light - Noto Sans Hebrew Medium - Noto Sans Hebrew Regular - Noto Sans JP Light - Noto Sans JP Medium - Noto Sans JP Regular - Noto Sans Light - Noto Sans Medium - Noto Sans Regular - Noto Sans SC Light - Noto Sans SC Medium - Noto Sans SC Regular - Noto Sans TC Light - Noto Sans TC Medium - Noto Sans TC Regular - Noto Sans Thai Light - Noto Sans Thai Medium - Noto Sans Thai Regular - Open Sans Bold - Open Sans Italic - Open Sans Regular - Open Sans Semibold - Roboto Bold - Roboto Condensed Italic - Roboto Italic - Roboto Medium - Roboto Regular - SeoulNamsan B - SeoulNamsan L - SeoulNamsan M As with sprites, if you want to use your own set of fonts, you will need to host these yourself. Warning Make sure that you are in compliance with any font licensing requirements before deploying maps with additional fonts. You can use a tool like our own open-source [`build_pbf_glyphs`](https://github.com/stadiamaps/sdf_font_tools/tree/main/build_pbf_glyphs) CLI utility or [MapLibre FontMaker](https://maplibre.org/font-maker/) to generate the SDF font glyphs. You will then need to update `glyphs` key in your style JSON accordingly. The [`text-font`](https://maplibre.org/maplibre-style-spec/layers/#text-font) property in a MapLibre Style is a list which specifies fonts in fallback order. This is quite handy, but introduces some complexity. We'll cover both approaches briefly. #### Combining Glyphs Upfront The easiest option is to never specify more than a single font in any font list. Then you can host your font glyphs in a directory of static files (as generated by `build_pbf_glyphs`). You *can* still have fallback fonts without any extra complexity server-side by combining glyphs upfront into "super fonts." For example, you can roll up Latin script bold font and a Japanese bold font into a single "bold" font. Let's call this "MyFont Bold." You just need to specify the fonts and a fallback order (much as you would in the MapLibre style JSON). You can then reference "MyFont Bold" in your style, and host the glyphs for MyFont Bold in a directory of static files. Refer to the [`build_pbf_glyphs` README](https://github.com/stadiamaps/sdf_font_tools/tree/main/build_pbf_glyphs) for usage instructions. #### Combining Glyphs Dynamically If you need to handle fallback fonts dynamically via a list in your style, your server will need to know how to handle Mapbox-style fontstack requests. These combine requests for multiple fonts into a long URL. Your server software then selects the glyphs in the specified fallback order. We have open-sourced the Rust crate, [`pbf_font_tools`](https://github.com/stadiamaps/sdf_font_tools/tree/main/pbf_font_tools), which has this logic. We use this ourselves and as part of `build_pbf_glyphs`. If you're using Node.js, have a look at [glyph-pbf-composite](https://github.com/mapbox/glyph-pbf-composite). ## Raster Maps Most customers ask us about custom raster styles because they are using Leaflet. If you want to keep using Leaflet, we have good news! You can use vector tiles in Leaflet with a custom style using the `maplibre-gl-leaflet` plugin. We put together a [tutorial](../tutorials/vector-tiles-with-leaflet/) on how to do this in just a few minutes. And this [example repository](https://github.com/stadiamaps/leaflet-custom-style) shows Leaflet in action with a custom style. If you are still sure that you need raster tiles for your custom style, [contact us](mailto:support@stadiamaps.com) for a quote. ## Further Reading The [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/) is the final authority on MapLibre styling. Even if you primarily use Maputnik for editing styles visually, this is still useful to have as a reference. ### Guides - [Changing the Map Label Language (guide)](../tutorials/changing-the-map-label-language/) - [Mapster WP Maps Plugin for WordPress (step-by-step tutorial)](../tutorials/wordpress-with-mapster/) # Map Style Library Stadia Maps offers multiple map styles, each with a different focus to help make the most of your map integration. This page showcases the styles we host at Stadia Maps. Quickly get started in popular frameworks like MapLibre GL JS, Leaflet, and OpenLayers with our example code. Build your own custom styles! Did you know? You can also [create your own custom style](../custom-styles/) to ensure your maps fit your application color scheme, focus, or other requirements perfectly. ## Stadia Maps Styles Our homegrown styles are the result of years of refinement based on user feedback around their use cases. ### Alidade Smooth Free Starter Standard Professional Our custom Alidade Smooth style is designed for maps that use a lot of markers or overlays. It features a muted color scheme and fewer points of interest to allow your added data to shine. [Get started with Alidade Smooth](../map-styles/alidade-smooth/) ### Alidade Smooth Dark Free Starter Standard Professional Alidade Smooth Dark, like its lighter cousin, is also designed to stay out of the way. It just flips the dark mode switch on the color scheme. With the lights out, your data can now *literally* shine. [Get started with Alidade Smooth Dark](../map-styles/alidade-smooth-dark/) ### Alidade Satellite Free Starter Standard Professional Carrying on the tradition of the Alidade family of styles, Alidade Satellite turns the earth itself into your canvas. This style uses satellite imagery as a base, and layers labels and outlines of major features on top to create a solid contextual backdrop for your data. [Get started with Alidade Satellite](../map-styles/alidade-satellite/) ### Outdoors Free Starter Standard Professional Make the great outdoors your playground. Based on the well-known OSM Bright style, the Stadia Outdoors style highlights useful outdoor features such as ski slopes, mountains, parks, and paths. [Get started with Outdoors](../map-styles/outdoors/) ## Stadia × Stamen Based on the original basemaps created for the Knight Foundation, the Stadia x Stamen partnership fuses Stamen's tradition of beautiful, functional maps with our strong and reliable platform, affordable and accessible to anyone. ### Stamen Toner Free Starter Standard Professional The most popular of the excellent styles from Stamen Design, these high-contrast B+W (black and white) maps are the perfect backdrop for your colorful and eye-catching overlays. [Get started with Stamen Toner](../map-styles/stamen-toner/) ### Stamen Terrain Free Starter Standard Professional Orient yourself with the Stamen terrain maps, featuring hill shading and natural vegetation colors. [Get started with Stamen Terrain](../map-styles/stamen-terrain/) ### Stamen Watercolor Free Starter Standard Professional Reminiscent of hand drawn maps, the watercolor maps from Stamen Design apply raster effect area washes and organic edges over a paper texture to add warm pop to any map. [Get started with Stamen Watercolor](../map-styles/stamen-watercolor/) ## Classic Styles Classic, familiar styles that you've probably seen around the web. ### OSM Bright Free Starter Standard Professional The OSM Bright style was developed as a sensible starting point for quickly making beautiful maps based on the OpenStreetMap database. It highlights the content in the map itself. We recommend using OSM bright where you are focused on providing directions, have minimal overlays or other data that might clash with the styling, or want a lot of POIs visible. Note that our outdoors style also works for many of these scenarios, but OSM Bright is a classic alternative. [Get started with OSM Bright](../map-styles/osm-bright/) # Add 3D Buildings to your Maps Free Starter Standard Professional Most maps are flat, looking straight down at the earth from above. But sometimes you need to look at things from another angle. [Navigation apps](../../sdks/ferrostar/), for example, often have a camera pitch between 45 and 60 degrees to show the area around and in front of the vehicle better. At this angle, your maps can really come to life with 3D buildings. This tutorial will show you how to add 3D buildings to any map style using MapLibre and vector basemap tiles from Stadia Maps. ## Build the Layer The look and feel of your map is controlled by a stylesheet using a JSON [MapLibre style](https://maplibre.org/maplibre-style-spec/). It defines the data sources and layers, which order rendering should happen in, and various attributes of the layers that make up your map. A [`fill-extrusion`](https://maplibre.org/maplibre-style-spec/layers/#fill-extrusion) layer lets us create a 3D effect by extruding portions of buildings from height information already present in the vector tile. The result isn't as detailed as a 3D model or point cloud, but it's *fast*, and saves precious data for mobile users. A 3D building layer definition ``` { "id": "3d-buildings", "source": "openmaptiles", "source-layer": "building", "filter": [ "!", [ "to-boolean", ["get", "hide_3d"] ] ], "type": "fill-extrusion", "minzoom": 13, "paint": { "fill-extrusion-color": "lightgray", "fill-extrusion-height": [ "interpolate", ["linear"], ["zoom"], 13, 0, 16, ["get", "render_height"] ], "fill-extrusion-base": [ "case", [">=", ["get", "zoom"], 16 ], ["get", "render_min_height"], 0 ] } } ``` If you're familiar with MapLibre style documents already, this might look familiar. The first few property names describe themselves: an `id` gives a layer a unique identifier, `minzoom` specifies the minimum zoom at which the layer will render, and so on. If you're starting from a [style](../../themes/) developed internally at Stadia Maps, it has an OpenMapTiles schema-compatible source named `openmaptiles`. If you're adding buildings to one of our Stamen-designed styles, change the source identifier to `stamen-omt`. The `filter` is an example of an [expression](https://maplibre.org/maplibre-style-spec/expressions/), which lets you make a decision according to some rules. If you've written LISP before, this might look like a predicate function with weird syntax. In our example, we are excluding features in the `building` layer with `hide_3d` set to a truth-y value. (The `hide_3d` property is set on building parts which are underground.) The `paint` property is where we specify how the building will look. The `fill-extrusion-color` determines the exterior color. We've selected a neutral light gray. The `fill-extrusion-height` and `fill-extrusion-base` properties determine how the building is extruded. The effect of our choices here is to make the building "scale in" as you zoom. ## Add the Layer to a Style ### Integrating into a Custom Style If you're building a [custom style](../../custom-styles/) already, just add the new layer where you'd like it in your JSON! This currently requires a bit of work, but we're working to make that easier. [Let us know](mailto:support@stadiamaps.com) if you'd like to be kept up to date on custom style hosting. ### Modifying an Existing Style Dynamically You can also modify an existing style in-place after it's loaded into the map! Use this approach with care, as things like layer identifiers or ordering may change over time. Here's an example of how you could do this in MapLibre GL JS. MapLibre Native offers similar APIs. ``` map.addLayer({ 'id': '3d-buildings', 'source': 'openmaptiles', 'source-layer': 'building', 'filter': [ "!", ["to-boolean", ["get", "hide_3d"] ] ], 'type': 'fill-extrusion', 'minzoom': 13, 'paint': { 'fill-extrusion-color': 'lightgray', 'fill-extrusion-height': [ 'interpolate', ['linear'], ['zoom'], 13, 0, 16, ['get', 'render_height'] ], 'fill-extrusion-base': ['case', ['>=', ['get', 'zoom'], 16], ['get', 'render_min_height'], 0 ] } }, labelLayerId // Replace this with the ID of a layer in the style; the new layer will be added below this ); ``` ## Full Example in MapLibre GL JS Bringing everything together, here is some sample code which adds a 3D buildings layer to one of our styles. To keep it relatively simple and future-proof, we add the buildings directly under the first `symbol` layer. To make experimenting easy, we've packaged the example code as a JSFiddle playground. Click the "Try it in JSFiddle" button to try it right from your web browser. [Try it in JSFiddle](#) ``` Vector Map Demo
``` ## Next Steps Ready to add maps with 3D buildings to your website or app? Sign up for a free Stadia Maps account to get started! [Get Started With a Free Account](https://client.stadiamaps.com/signup/) If you want to craft even more detailed building styles, the MapLibre style [documentation](https://maplibre.org/maplibre-style-spec/layers/#fill-extrusion) covers other styling options including patterns, gradients, and more. Finally, if you're building a navigation experience, check out [Ferrostar](../../sdks/ferrostar/), our highly extensible navigation SDK. # Changing Specific Place Labels on the Map Free Starter Standard Professional Have you found wanted to change the label of a particular feature on your map? Maybe you have to display a political viewpoint, or just want to add your own label to the map to make a place more prominent? This tutorial will cover what you need to know, along with example code for MapLibre GL JS and MapLibre GL Leaflet. For local development on a web server at `localhost` or `127.0.0.1`, you can get started without any API keys or domain setup! For mobile, backend, and non-local web development, you'll need either domain auth or an API key. If you don't already have a Stadia Maps account, [sign up for a free](https://client.stadiamaps.com/signup/) to get started. Domain-based authentication Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). 1. Click "Manage Properties." 1. Under "Authentication Configuration," click the button to add your domain. API key authentication ### Authenticating requests via API key You can authenticate your requests by adding an API key to the query string or HTTP header. Example URL with an API key placeholder ``` https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY ``` Example Authorization header with an API key placeholder ``` Authorization: Stadia-Auth YOUR-API-KEY ``` The simplest is to add a query string parameter `api_key=YOUR-API-KEY` to your request URL. For example, to access the `/tz/lookup` API endpoint, your request URL might look like this. You can also use an `Authorization` HTTP header instead of a query string as shown below. Don't forget the `Stadia-Auth` prefix! ### How to get an API key Don't have an API key yet? Follow these easy steps! 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). (If you don't have an account yet, sign up for free; no credit card required!) 1. Click "Manage Properties." 1. If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page. 1. Under "Authentication Configuration," you can generate, view or revoke your API key. #### Video: How to generate your API key ## Finding the label to change The simplest approach to changing labels is to modify your map style. Normally the `text-field` is a simple property getter, like `["get", "name:en"]`. We'll replace the simple getter with conditional logic based on the ID. For example, if you want to rename the Gulf of Mexico, here's how you'd change your style: ``` "text-field": [ - ["get", "name:en"] + "case", + ["==", ["id"], 3056391900], + "Gulf of America", + ["get", "name:en"] ], ``` While the mechanism is extremely simple, it *does* rely on you knowing two things: the feature and layer ID. We've made it easy to get these with the map below. Just find the label you're looking for, click on it, and copy the ID and source layer. [© Stadia Maps](https://stadiamaps.com/) [© OpenMapTiles](https://openmaptiles.org/) [© OpenStreetMap](https://www.openstreetmap.org/copyright) ## Changing the label Now that we have a feature ID and a source layer, we can go about modifying our stylesheet. Here's how you can do it on the fly in JavaScript! To change the layer in MapLibre GL JS, you'll need to add some code in a style load listener. For a full example of how to set up a full-page map, check our [quickstart tutorial](../vector-maps-with-maplibre-gl-js/). ``` var map = new maplibregl.Map({ container: 'map', style: 'https://tiles.stadiamaps.com/styles/alidade_smooth.json', // Style URL; see our documentation for more options center: [-87, 24], // Initial focus coordinate zoom: 4 }); map.on('style.load', (e) => { const style = map.getStyle(); for (const targetLayer of style.layers) { // We're interested in layers that display items from water_name if (targetLayer["source-layer"] === 'water_name') { // Add some switching logic for the text-field, matching against the feature ID: 3056391900 // If you have another feature you need update, you will need to make adjustments to the case condition below targetLayer.layout['text-field'] = [ 'case', ["==", ["id"], 3056391900], "Gulf of America", ["get", "name:en"] ]; } } map.setStyle(style); }); ``` You can change labels in leaflet too, if you're using the MapLibre GL Leaflet plugin. For a full example of how to set up vector tiles in Leaflet, check our [quickstart tutorial](../vector-tiles-with-leaflet/). To change the layer in MapLibre GL Leaflet, you'll need to add some code in a style load listener. ``` const lmap = L.map('map').setView([24, -87], 5); const gl = L.maplibreGL({ style: 'https://tiles.stadiamaps.com/styles/alidade_smooth.json', attribution: '© Stadia Maps, © OpenMapTiles © OpenStreetMap', }).addTo(lmap); const map = gl.getMaplibreMap(); map.on('style.load', (e) => { const style = map.getStyle(); for (const targetLayer of style.layers) { // We're interested in layers that display items from water_name if (targetLayer["source-layer"] === 'water_name') { // Add some switching logic for the text-field, matching against the feature ID: 3056391900 // If you have another feature you need update, you will need to make adjustments to the case condition below targetLayer.layout['text-field'] = [ 'case', ["==", ["id"], 3056391900], "Gulf of America", ["get", "name:en"] ]; } } map.setStyle(style); }); ``` ## Next Steps And that's it. The above examples are extendable to more features by adding additional cases. If you're already hosting a custom style, you may rather edit the style directly, but this demonstrates the overall approach. Once you're ready to move beyond `localhost` testing, sign up for a free Stadia Maps account, and we'll walk through the next steps to registering your domain or getting an API key. [Get Started With a Free Account](https://client.stadiamaps.com/signup/) # How to Change the Language of Place Labels Free Starter Standard Professional Our [default map styles](../../themes/) show the names of places (countries, cities, towns, waterways, etc.) in up to two languages by default. The first is the "Latin" name (the local name if it happens to use a Latin script; otherwise the English name or a romanization), and the second is the local name (if the local name does not use a Latin script). We chose this approach to preserve readability for a large audience while still showing local names. However, some applications will benefit from explicit localization. This tutorial will show you how! ## Editing the style The first step is to pick the style you want to localize. You can start with [one of our own](../../themes/), or [design your own](../../custom-styles/). Next, it's time to customize the style! The property you need to look at is `text-field`, under the `layout` property of each layer. Our styles come with a rather complex expression that does string concatenation and fallback logic. The simplest way to change language labels is to replace the `text-field` key with a value like `{name:fr}`. The braces tell the renderer that it should use the value of the field for the text label. In this case, it will use the `name:fr` field, thus always picking the French name of the feature. List of supported language codes - `am` (Amharic) - `ar` (Arabic) - `az` (Azerbaijani, Latin) - `be` (Belarusian) - `bg` (Bulgarian) - `br` (Breton, Latin) - `bs` (Bosnian, Latin) - `ca` (Catalan, Latin) - `co` (Corsican, Latin) - `cs` (Czech, Latin) - `cy` (Welsh, Latin) - `da` (Danish, Latin) - `de` (German, Latin) - `el` (Greek) - `en` (English, Latin) - `eo` (Esperanto, Latin) - `es` (Spanish, Latin) - `et` (Estonian, Latin) - `eu` (Basque, Latin) - `fi` (Finnish, Latin) - `fr` (French, Latin) - `fy` (Western Frisian, Latin) - `ga` (Irish, Latin) - `gd` (Scottish Gaelic, Latin) - `he` (Hebrew) - `hr` (Croatian, Latin) - `hu` (Hungarian, Latin) - `hy` (Armenian) - `id` (Indonesian, Latin) - `is` (Icelandic, Latin) - `it` (Italian, Latin) - `ja` (Japanese) - `ja_kana` (Japanese Kana form) - `ka` (Georgian) - `kk` (Kazakh) - `kn` (Kannada) - `ko` (Korean) - `ku` (Kurdish, Latin) - `la` (Latin, Latin) - `lb` (Luxembourgish, Latin) - `lt` (Lithuanian, Latin) - `lv` (Latvian, Latin) - `mk` (Macedonian) - `mt` (Maltese, Latin) - `ml` (Malayalam) - `nl` (Dutch, Latin) - `no` (Norwegian, Latin) - `oc` (Occitan (post 1500), Latin) - `pl` (Polish, Latin) - `pt` (Portuguese, Latin) - `rm` (Romansh, Latin) - `ro` (Romania, Latin) - `ru` (Russian) - `sk` (Slovak, Latin) - `sl` (Slovene, Latin) - `sq` (Albanian, Latin) - `sr` (Serbian, Cyrillic) - `sr-Latn` (Serbian, Latin) - `sv` (Swedish, Latin) - `th` (Thai) - `tr` (Turkish, Latin) - `uk` (Ukrainian) - `zh` (Chinese) But what if the city, mountain, river, etc. doesn't have a French name? You can easily add fallback logic using the `coalesce` expression. For example, the following will use a French name if one exists, falling back to a Latin-based name next, and then finally falling back to the local name if there is no Latin name in our data. ``` "text-field": [ "coalesce", [ "get", "name:fr" ], [ "get", "name:latin" ], [ "get", "name" ] ] ``` Do this for every layer in your style that makes sense to localize. Some (for example, route numbers) can be left alone. ## Using the style Rather than using our hosted styles, you'll need to point your map rendering library (MapLibre, Leaflet, etc.) at the new style. You will need to host this on your web server or bundle it with your app as noted in our guide on [creating a custom style](../../custom-styles/). We've collected everything together in an [example repository](https://github.com/stadiamaps/leaflet-custom-style). The example uses Leaflet, but it works equally well in MapLibre GL JS or any other framework that supports MapLibre JSON styles. # Map Tiles and Static Images # Raster Map Tiles While vector tiles have replaced the classic image grid for many applications, raster map tiles are battle-tested and easy to render. They also benefit from a rich ecosystem of rendering libraries like OpenLayers and Leaflet. All of our house styles are available as PNG raster tiles in 256x256 px and 512x512 px "retina" sizes. ## Tile URL Format Most renderers use a format string like the one below and will automatically replace the placeholders for you. The only thing you'll need to replace yourself in most cases is the `
``` ### Tangram Tangram offers a number of unique features compared to other vector renderers, including custom GLSL shaders, unique 3D rendering customizations, and custom camera and lighting controls. We don't yet offer official styles, but have an experimental tool that attempts to migrate our JSON styles to Tangram ones. You can follow the development of the [Cartogrify](https://github.com/stadiamaps/cartogrify) project on GitHub. ## Further Reading For more details on MapLibre GL JS, check out the [official documentation](https://maplibre.org/maplibre-gl-js/docs/). You can also explore the [Leaflet](https://leafletjs.com/), [OpenLayers](https://openlayers.org/), and [Tangram](https://github.com/tangrams/tangram) projects. # Switching from Raster to Vector Map Tiles If you've ever zoomed in and out of a map quickly, you probably noticed little blank squares that filled in like a mosaic. This is a map tile. Most interactive electronic maps are constructed from tiles, which are then stitched together to form a complete interactive map. Map tiles for interactive maps come in two main flavors: raster and vector. Raster tiles have been around for decades, but are gradually being replaced by a vector tiles, a newer format which has unique advantages for most applications. Whether you're a seasoned developer looking to improve your maps or planning your first maps integration from scratch, this guide is for you. Let's get started! ## Background ### What are raster tiles? As we mentioned in the intro, map tiles can be broadly classified as either raster or vector. Raster tiles are the simplest to understand, as they are just PNG or JPG images that get stitched together in a grid, so we'll start here. #### Advantages Raster tiles have been around for a long time, and even today, they have a number of unique advantages. - **Simplicity** - Just about every device can render a PNG or JPG image, and it's very easy to build a performant renderer around these. Additionally, raster tiles don't require any other resources (such as fonts or icons) or special logic to render. - **Specificity** - Map tiles simplify a *lot* of data into a form that's useful for the user. If you are working with a minimalist map style (like our Alidade Smooth family), raster tiles can be more bandwidth efficient, as they only contain the raw visible pixels. #### Limitations While raster tiles are battle tested and supported pretty much everywhere, they also have some inherent limitations. - **Inflexibility** - You cannot change much about raster tiles. If you want to hide a certain layer, change the language of labels, or do just about anything else to alter the appearance of the tiles, you're out of luck. - **Scalability** - Raster map tiles cannot be scaled up and down, meaning you need to send 4x as many pixels over the network for your maps to look good on modern "high DPI" displays. This problem also shows up when zooming in to a raster map as the tiles become blurry until the new ones are loaded. ### What are vector tiles? Vector tiles are a newer development, and are broadly viewed as the future of digital interactive maps. Rather than pixels, vector tiles contain a mathematical description of the geometry as well as structured data about each feature on the map. #### Advantages - **Flexibility** - Vector tiles aren't just raw pixels; the actual *data* is preserved in the tile. This means that you can seamlessly [change the language](../../tutorials/changing-the-map-label-language/) of text labels, change the color scheme to suit your brand, or even switch styles dynamically based on the time of day or the user's device preferences. You can even completely change the camera angle for a 3D perspective. - **Scalability** - Since vector shapes are expressed in mathematical terms, they can be scaled up and down smoothly. For example, when the user zooms in, they'll get a smooth scale-in without any pixelation. This is especially relevant on mobile devices, where users are used to continuous zoom for most applications rather than discrete steps. - **Cost** - Many vendors, including Stadia Maps, charge per tile request. Switching to vector tiles can mean significant savings, as vector tiles cover a larger area. On average, we see users switching to vector making approximately 60% fewer tile requests. #### Limitations - **Complexity** - While vector tiles provide a lot of flexibility, this comes at the cost of complexity. Tiles need to be rendered client-side, and this may create performance concerns for older or embedded applications. Additionally, since vector maps require additional resources to be present, the initial map load typically involves a greater number of network requests. - **Size** - For applications only requiring a low level of detail that don't utilize any of the 3D perspective features of vector tiles, the vector tiles can weigh a bit more. However, this is somewhat offset since all zooming past level 14 can use the information in the z14 tile. ## Recap: Which should I use? We've covered a lot of ground. To summarize, vector tiles offer greater flexibility, look great on any screen, and typically reduce costs by around 60%. However, if your application is targeting older devices or doesn't need a high level of detail (for example, our [Alidade Smooth](../../map-styles/alidade-smooth/) and [Alidade Smooth Dark](../../map-styles/alidade-smooth-dark/) styles), raster tiles are not necessarily a bad option. Now, let's dive into some practical tips on switching to vector tiles. ## How can I switch to vector tiles? Switching is easy. The first step is to select a [style](../../themes/) from our gallery (you can also [build your own](../../custom-styles/)). You'll want to copy the vector style URL. Let's dive into using vector styles with the most popular frameworks! ### Switching to MapLibre MapLibre provides the greatest flexibility and feature support when it comes to vector tile rendering. If you want the best looking maps, a 3D camera, or dynamic styling, MapLibre is the way to go. #### Web We have an [in-depth tutorial](../../tutorials/vector-maps-with-maplibre-gl-js/) that covers the basics. For most use cases, the transition is easy: just swap out Leaflet or a similar renderer for MapLibre GL JS and use the code snippets or URLs of one of our styles. In addition to the tutorial, which covers creating a basic map and adding markers, we've compiled some resources below which cover the most common questions we receive: - **Marker clustering** - When you have a map with a lot of markers, you typically want to cluster them into groups. This is not quite as intuitive as in some other frameworks (particularly Leaflet). We have a [tutorial](../../tutorials/clustering-styling-points-with-maplibre/) to get you started. - **Adding overlays** - MapLibre GL JS supports a wide variety of overlays. We have tutorials covering [drawing polylines (ex: a route)](../../tutorials/getting-directions-in-javascript-from-geospatial-apis-maplibre/) and [polygons](../../tutorials/display-isochrones-on-a-map/). #### Mobile We have quickstart tutorials to get you going on native iOS and Android, Flutter, and React Native. You can find all of these in our [Native & Multi-platform maps overview](../../native-multiplatform/overview/). ### Using vector tiles with Leaflet If you're already using Leaflet and would prefer not to switch, you can add vector rendering support with the [maplibre-gl-leaflet](https://github.com/maplibre/maplibre-gl-leaflet) plugin. This isn't quite as powerful as MapLibre GL JS, but it's the quickest migration path to most of the benefits. #### Vanilla HTML and JavaScript You can add the plugin by adding a few lines to the `` section of your page or via `npm install --save @maplibre/maplibre-gl-leaflet maplibre-gl`. ``` ``` All you need to do to switch to vector is create your tile layer using `L.maplibreGL` instead of `L.tileLayer`. Here is an example using Alidade Smooth; you can substitute it with your [preferred style](../../themes/). ``` - L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png', { - maxZoom: 20, + L.maplibreGL({ + style: 'https://tiles.stadiamaps.com/styles/alidade_smooth.json', attribution: '© Stadia Maps, © OpenMapTiles © OpenStreetMap', }).addTo(map); ``` If you'd like to see a complete vector integration example with a line-by-line walkthrough and a JSFiddle playground, check out our tutorial on [vector tiles with Leaflet](../../tutorials/vector-tiles-with-leaflet/). #### React Leaflet If you're using React Leaflet, you can switch by adding a simple component and using that for your map tile layer. Our [in-depth tutorial](../../tutorials/vector-tiles-with-react-leaflet/) will show you exactly what to do. ### Using vector tiles with OpenLayers Some more advanced web mapping use cases require the power of OpenLayers. You can add support for OpenLayers using the [`ol-mapbox-style`](https://github.com/openlayers/ol-mapbox-style) plugin. This is not supported quite as well as Leaflet yet, but it is a great option if you need the power of OpenLayers and want to switch to vector tiles. First, you will need to load the plugin. You can either add this line to your HTML `` section or `npm install --save ol-mapbox-style@13.4.0`. ``` ``` Then, you can use `olms.apply`, passing either the ID of the HTML element to use, or an existing OpenLayers map instance. ``` olms.apply('map', 'https://tiles.stadiamaps.com/styles/alidade_smooth_dark.json').then(function(map) { // Callback to configure the map if necessary }); ``` ## Wrapping up We've covered the differences between raster and vector tiles, and when each is most appropriate. For the majority of applications, which benefit from vector tiles, we've gone over the most popular frameworks, highlighted the major gotchas, and linked to in-depth tutorials where available. If we missed something that's got you stumped, reach out to us via [email](mailto:support@stadiamaps.com) or our social media channels (you can find them in the footer). Once you're ready to go live with your vector map, sign up for a free Stadia Maps account, and we'll walk through the next steps to registering your domain or getting an API key. [Get Started With a Free Account](https://client.stadiamaps.com/signup/) # Maps for the Web # Interactive Web Maps If you're looking to get started with interactive maps on the web, you're in the right place! Let's get started with the best libraries for based on your preferred tech stack and use case. ## React - **MapLibre React Components** ______________________________________________________________________ MapLibre React components are the simplest way to get started building maps in React. This library provides simple components and gets out of the way. It aims to be as light as possible, adding little weight on top of MapLibre. [Get Started with MapLibre React Components](../tutorials/getting-started-with-maplibre-react-components/) - **React Leaflet** ______________________________________________________________________ React Leaflet is a tried and true option with a large feature set. It leverages the rich Leaflet ecosystem, and makes it easy to build interactive maps with marker clustering, custom annotations and popups, and more. [Get Started with React Leaflet (Vector)](../tutorials/vector-tiles-with-react-leaflet/) [Get Started with React Leaflet (Raster)](../tutorials/getting-started-with-react-leaflet/) - **Custom React Component** ______________________________________________________________________ Need more advanced features like 3D perspective or restyling client-side? You can build a component that's customised for your application and data flow using MapLibre GL JS to do the heavy lifting. Our tutorial on the vanilla JavaScript API covers the basics, empowering you to [build your own component](https://react.dev/learn/thinking-in-react). [Learn MapLibre GL JS](../tutorials/vector-maps-with-maplibre-gl-js/) ## Vue - **Vue Leaflet** ______________________________________________________________________ Vue Leaflet is the easiest way to build maps with Vue 3. While you won't get the glitzy 3D effects and vector rendering of MapLibre GL JS, Vue Leaflet leverages the rich Leaflet ecosystem, which makes it extremely easy to build maps with marker clustering, custom annotations and popups, and more. [Get Started with Vue Leaflet](../tutorials/getting-started-with-vue-leaflet/) - **Custom Vue Component** ______________________________________________________________________ Need more advanced features like 3D perspective or restyling client-side? You can build a component that's customised for your application and data flow using MapLibre GL JS to do the heavy lifting. Our tutorial on the vanilla JavaScript API covers the basics, empowering you to [build your own component](https://vuejs.org/guide/essentials/component-basics.html). [Learn MapLibre GL JS](../tutorials/vector-maps-with-maplibre-gl-js/) ## Vanilla JS - **MapLibre GL JS** ______________________________________________________________________ MapLibre GL JS is the most advanced vector tile renderer and supports dynamic styling, 3D perspective, hillshading, and more. Our tutorial will get you started, and point to further examples of how to handle the more complex use cases. [Get Started with MapLibre GL JS](../tutorials/vector-maps-with-maplibre-gl-js/) - **Leaflet** ______________________________________________________________________ Leaflet is probably the best known and simplest of all map rendering libraries. Its gentle learning curve yet powerful APIs make it one of the most popular renderers around. And if the base library can't do something out of the box, check out the long list of [available plugins](https://leafletjs.com/plugins.html). [Get Started with Leaflet (Raster)](../tutorials/raster-maps-with-leaflet/) [Get Started with Leaflet + MapLibre (Vector)](../tutorials/vector-tiles-with-leaflet/) - **OpenLayers** ______________________________________________________________________ OpenLayers has a dizzying array of features, integrates with many OGC APIs, supports vector layers in multiple formats, and [a *lot* more](https://openlayers.org/en/latest/examples/). If you're a GIS professional, OpenLayers needs no introduction. Stadia Maps is a built-in tile provider from OpenLayers v8.0.0, and is quite easy to use in prior versions. [Get Started with OpenLayers](../tutorials/raster-maps-with-openlayers/) Other vector renderers Our vector tiles use the Mapbox Vector Tile format, and are compatible with several [other renderers](../vector/#alternative-renderers), but we cannot provide official styles and support for these at the moment. If you'd like help getting started and your framework isn't mentioned, [let us know](mailto:support@stadiamaps.com)! # Turn your Maps into a 3D Globe Free Starter Standard Professional Most maps on the web are flat, but it doesn't have to be this way! Whether you're trying to avoid the distortions of the Mercator projection or just trying to make your map stand out, a globe view will do the trick. And it only takes a few lines of code! This tutorial will show you how to activate the new globe projection in your maps using MapLibre GL JS. If you don't have a map set up yet and need some help getting started, check out our [other web tutorials](../../maps-for-web/) to fill in the gaps. For local development on a web server at `localhost` or `127.0.0.1`, you can get started without any API keys or domain setup! For mobile, backend, and non-local web development, you'll need either domain auth or an API key. If you don't already have a Stadia Maps account, [sign up for a free](https://client.stadiamaps.com/signup/) to get started. Domain-based authentication Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). 1. Click "Manage Properties." 1. Under "Authentication Configuration," click the button to add your domain. API key authentication ### Authenticating requests via API key You can authenticate your requests by adding an API key to the query string or HTTP header. Example URL with an API key placeholder ``` https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY ``` Example Authorization header with an API key placeholder ``` Authorization: Stadia-Auth YOUR-API-KEY ``` The simplest is to add a query string parameter `api_key=YOUR-API-KEY` to your request URL. For example, to access the `/tz/lookup` API endpoint, your request URL might look like this. You can also use an `Authorization` HTTP header instead of a query string as shown below. Don't forget the `Stadia-Auth` prefix! ### How to get an API key Don't have an API key yet? Follow these easy steps! 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). (If you don't have an account yet, sign up for free; no credit card required!) 1. Click "Manage Properties." 1. If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page. 1. Under "Authentication Configuration," you can generate, view or revoke your API key. #### Video: How to generate your API key ## Upgrade MapLibre to v5 or higher [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs) added support for globe rendering in version 5. So the first step is make sure your project is using the [latest release](https://github.com/maplibre/maplibre-gl-js/releases) (e.g. by upgrading `package.json` or updating your `
``` ## Next Steps Looking for more inspiration? Check out the [MapLibre GL JS Examples](https://maplibre.org/maplibre-gl-js/docs/examples/) to discover other ways to enhance your maps. Once you're ready to move beyond `localhost` testing, sign up for a free Stadia Maps account, and we'll walk through the next steps. [Get Started With a Free Account](https://client.stadiamaps.com/signup/) # Clustering and styling points with MapLibre GL JS Free Starter Standard Professional When you are adding a plethora points to your maps, they can quickly become cluttered and difficult to read, navigate, and interact with. That's why [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/API/) provides you with the ability to cluster and stylize your points. In this tutorial, you'll learn how to add a map to your webpage, add points from a GeoJSON data source, along with stylizing and clustering the points. ## Drawing a map with point clusters Let's dive in with some example code to accomplish this. The code below is based on MapLibre's [create and style clusters](https://maplibre.org/maplibre-gl-js/docs/examples/cluster/) example, adding an explanation of the code and adapting it for Stadia Maps. For local development on a web server at `localhost` or `127.0.0.1`, you can get started without any API keys or domain setup! For mobile, backend, and non-local web development, you'll need either domain auth or an API key. If you don't already have a Stadia Maps account, [sign up for a free](https://client.stadiamaps.com/signup/) to get started. Domain-based authentication Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). 1. Click "Manage Properties." 1. Under "Authentication Configuration," click the button to add your domain. API key authentication ### Authenticating requests via API key You can authenticate your requests by adding an API key to the query string or HTTP header. Example URL with an API key placeholder ``` https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY ``` Example Authorization header with an API key placeholder ``` Authorization: Stadia-Auth YOUR-API-KEY ``` The simplest is to add a query string parameter `api_key=YOUR-API-KEY` to your request URL. For example, to access the `/tz/lookup` API endpoint, your request URL might look like this. You can also use an `Authorization` HTTP header instead of a query string as shown below. Don't forget the `Stadia-Auth` prefix! ### How to get an API key Don't have an API key yet? Follow these easy steps! 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). (If you don't have an account yet, sign up for free; no credit card required!) 1. Click "Manage Properties." 1. If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page. 1. Under "Authentication Configuration," you can generate, view or revoke your API key. #### Video: How to generate your API key To make experimenting easy, we've packaged the example code as a JSFiddle playground. Click the "Try it in JSFiddle" button to try it right from your web browser. [Try it in JSFiddle](#) ``` Create and style clusters with MapLibre GL JS and Stadia Maps
``` ### Code Walkthrough First, we'll add some opening HTML content that will make the document standard compliant: ``` Create and style clusters with MapLibre GL JS and Stadia Maps ``` Next, we'll include the MapLibre library files: ``` ``` Now, we'll add CSS to define the body, the map ID, and then close the `` tag: ``` ``` With the `` details in, we can now add the body for our page. This is where we'll create the map element: ```
``` Next, we'll add the JavaScript for: - initializing the map, specifying the `container`, `style`, `center`, and `zoom`: ``` ``` Finally, we'll close up the `` and `` tags: ``` ``` And that's it. Congratulations; you can now visualize data with point clustering! All the code, put together, will match the code at the start of this section. ## Next Steps This tutorial gives you a solid foundation in how to use MapLibre GL JS to add GeoJSON point data to a map, interactive click events, along with stylizing the points and clusters. You can get additional inspiration from what others have built at the [MapLibre GL JS Examples](https://maplibre.org/maplibre-gl-js/docs/examples/) page. They have in-depth examples covering everything from GeoJSON lines to interactive time sliders. And don't forget to check out the [plugins](https://maplibre.org/maplibre-gl-js/docs/plugins/) and the rest of the [MapLibre GL JS documentation](https://maplibre.org/maplibre-gl-js/docs/API/) either. Once you're ready to move beyond `localhost` testing, sign up for a free Stadia Maps account, and we'll walk through the next steps. [Get Started With a Free Account](https://client.stadiamaps.com/signup/) # Getting Started with MapLibre React Components Free Starter Standard Professional Adding maps to your React-based web app has never been easier. [React Leaflet](../getting-started-with-react-leaflet/) is a solid choice, particularly when you need advanced functionality like marker clustering. But if you want something lean, optimized for vector tiles, and designed exclusively for MapLibre (like the globe view!), MapLibre React Components are worth a look. This tutorial will walk you through setting up a basic map, adding markers, and a dismissable popup. ## Create a React Application If you don't have an existing React application, starting one is straightforward with `npm create`. ``` npm create vite@latest my-app ``` Follow the prompts, selecting "React" as the framework, and your language of preference (we recommend TypeScript, but JavaScript works alright too). Default CSS The template projects come with a lot of default CSS. We completely ignore `App.css`, and replace `index.css` with the following minimal code: ``` :root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; } html, body, #root { margin: 0; width: 100%; height: 100%; background-color: #222; } ``` ## Install Dependencies The core of our map integration will rely on MapLibre React Components. Install it using `npm` or your preferred package manager. You'll also need `maplibre-gl`. ``` npm install maplibre-gl maplibre-react-components ``` ## Set Up Your Map Before adding the map to your component, we need to import the MapLibre stylesheet. We'll import this directly from the `maplibre-gl` package. ``` import "maplibre-gl/dist/maplibre-gl.css"; ``` Next, we'll need the `RMap` component. ``` import { RMap } from 'maplibre-react-components'; ``` Now we're ready to add a map. Find the area where you'd like it to appear in your React component. Then, add the `RMap` component like so: ```jsx ``` You can even configure binding to React state, and the map will update automatically! ## Add a Marker To provide more context to your users, you can add markers to your map. For example, you may have a set of nearby hotels, sights to see along a tour route, or favorite locations saved by the user. MapLibre React Components includes the `RMarker` component which makes this easy. Here's how you'd add a marker to the map. Note that the `RMarker`s should be added as children of the `RMap`! ``` ``` ## Making the Marker Interactive You can make the marker interactive using events like `onClick`, `onDragStart`, and `onDragEnd`. One popular use is making a popup appear with some extra details. We can use React state and the `RPopup` component provided by MapLibre React Components to add a popup like this: ``` Kultuurikatel (Tallinn Creative Hub) ``` The `markerPopupOffset` utility (also provided by `maplibre-react-components`) automatically sets the offset for the popup, so that it appears relative to the marker. ## Bringing it all Together Let's bring it all together now with a bit of React state so that we incorporate the click events. We'll make the popup visible by default, dismiss it when clicking anywhere else on the map (usually this means the user wants to dismiss it), and toggle visibity when clicking the marker. (You can also mentally replace "click" with "tap" by the way; this works on mobile too!). ``` import 'maplibre-gl/dist/maplibre-gl.css'; import { markerPopupOffset, RMap, RMarker, RPopup } from 'maplibre-react-components'; import type {LngLatLike} from 'maplibre-gl'; import {useState} from 'react'; function App() { // NOTE: coordinates are in longitude, latitude order, // NOT latitude, longitude as is commonly written! const kultuuriKatel: LngLatLike = [24.750592, 59.44435]; const [showPopup, setShowPopup] = useState(true); return ( { // Hide the popup when clicking on the map setShowPopup(() => false); }} // BONUS: Use the new globe projection; zoom out for the effect onLoad={(e) => e.target.setProjection({type: 'globe'})} > { e.stopPropagation(); // Toggle popup visibility when clicking on the marker setShowPopup((s) => !s); }}/> {showPopup && ( Kultuurikatel (Tallinn Creative Hub) )} ) } export default App ``` ## Next Steps MapLibre React Components can do a lot more! Refer to the [official documentation](https://maplibre-react-components.pentatrion.com/). Once you're ready to deploy your app, sign up for a free Stadia Maps account, and we'll walk through the next steps to get your domain authenticated. [Get Started With a Free Account](https://client.stadiamaps.com/signup/) # Getting Started with React Leaflet Free Starter Standard Professional If you need to visualize geospatial data in a web application, using [React](https://react.dev/) can greatly simplify your life as a developer. The benefits are especially obvious if you're working with large amounts of data or need to respond to filters and other user or backend actions. This tutorial will show you how to use [Leaflet](https://leafletjs.com/), a battle-tested mapping library, with React to make an interactive map of every video arcade in Japan. Demo Code You can clone the full code for this tutorial from [GitHub](https://github.com/stadiamaps/react-leaflet-demo/) and follow along to save typing. ## Create a React App If you don't have an existing React app, it's easy to create one! ``` npx create-react-app my-app ``` ## Install Dependencies We'll use Leaflet and its React wrapper, [React Leaflet](https://react-leaflet.js.org/) as the core map components. [react-leaflet-cluster](https://github.com/akursat/react-leaflet-cluster) will help us group nearby markers into clusters. You can install these using `npm` or your preferred package manager. ``` cd my-app npm install --save leaflet react-leaflet react-leaflet-cluster ``` ## Download Data We also need some data to visualize! We've already done the work for you and created a [JSON file](https://github.com/stadiamaps/react-leaflet-demo/blob/main/src/arcades.json) of all the arcades in Japan, which you can download and use in your project. ## Import and Setup Before we get to the maps, you'll need some boilerplate at the top of your component. If you don't import the Leaflet CSS, styling of many elements (most obviously the markers) will break. ``` import 'leaflet/dist/leaflet.css' import {MapContainer, Marker, Popup} from 'react-leaflet' import L from 'leaflet' import MarkerClusterGroup from "react-leaflet-cluster"; import {MapLibreTileLayer} from "./MapLibreTileLayer.tsx"; import arcades from './arcades.json' ``` You may also need to include the following JS right after the imports, depending on your webpack configuration. See this [GitHub Issue](https://github.com/PaulLeCam/react-leaflet/issues/255) for details. ``` delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'), iconUrl: require('leaflet/dist/images/marker-icon.png'), shadowUrl: require('leaflet/dist/images/marker-shadow.png') }); ``` Finally, you'll need to add some CSS to set the height of the map. If the map control doesn't have a specified height, it won't show up at all! ``` .full-height-map { height: 100vh; } ``` ## Add a Map Now we're ready to start adding a map! In React Leaflet, we do this with the `MapContainer` component, which we customize with a few attributes. We then add a `TileLayer` which tells Leaflet where to get the basemap tiles. Tip Check out the [library](../../themes/) for more raster map styles. What does maxBounds do? The map parameters mostly have self-explanatory names, but `maxBounds` deserves a quick explanation. If you don't set this, scrolling east past Japan will "warp" around back to the US (fine), but your markers will not be visible when you get around to Japan again! ``` {/* TODO: Add markers */} ``` ## Add Some Markers As part of the tutorial, we've provided Japanese arcade locations in a format called [GeoJSON](https://geojson.org/). We won't dive too deep into the details here, but it contains an array of geometric objects called features. Each one contains geometry information (in our case, latitude and longitude) and metadata (the name of the arcade). We can turn this raw data into markers with the `map` function, generating a marker for each arcade. We'll even attach a popup that shows up on click/tap. You can put pretty much whatever you want in the popup markup-wise, and can even style them using CSS! ``` {arcades.features.map((arcade, index) => ( {arcade.properties.name}
{arcade.properties['name:en']}
))} ``` ## Cluster Markers into Groups Japan has quite a few arcades and, as you might guess, they tend to be clustered in dense urban areas. Drawing hundreds of markers in a small area isn't particularly efficient for your web browser, nor does it look very good. We can make our arcade map much nicer by *clustering* markers into groups, only showing individual markers if there is enough space. All you have to do is wrap the markers in a `MarkerClusterGroup`. Magic! ``` {/* Markers */} ``` ## Bring it all Together We now have all the elements for our Japanese arcade map! We've put all the pieces together for you on [GitHub](https://github.com/stadiamaps/react-leaflet-demo/) to save typing. For local development on a web server at `localhost` or `127.0.0.1`, you can get started without any API keys or domain setup! For mobile, backend, and non-local web development, you'll need either domain auth or an API key. If you don't already have a Stadia Maps account, [sign up for a free](https://client.stadiamaps.com/signup/) to get started. Domain-based authentication Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). 1. Click "Manage Properties." 1. Under "Authentication Configuration," click the button to add your domain. API key authentication ### Authenticating requests via API key You can authenticate your requests by adding an API key to the query string or HTTP header. Example URL with an API key placeholder ``` https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY ``` Example Authorization header with an API key placeholder ``` Authorization: Stadia-Auth YOUR-API-KEY ``` The simplest is to add a query string parameter `api_key=YOUR-API-KEY` to your request URL. For example, to access the `/tz/lookup` API endpoint, your request URL might look like this. You can also use an `Authorization` HTTP header instead of a query string as shown below. Don't forget the `Stadia-Auth` prefix! ### How to get an API key Don't have an API key yet? Follow these easy steps! 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). (If you don't have an account yet, sign up for free; no credit card required!) 1. Click "Manage Properties." 1. If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page. 1. Under "Authentication Configuration," you can generate, view or revoke your API key. #### Video: How to generate your API key ## Next Steps React Leaflet has a lot of features not covered in this tutorial, including shape layers, draggable markers, and tooltips. Check out their [documentation](https://react-leaflet.js.org/) to learn more. Once your amazing app is ready to move beyond `localhost`, sign up for a free Stadia Maps account, and we'll walk through the next steps. [Get Started With a Free Account](https://client.stadiamaps.com/signup/) # Getting Started with Vue 3, Vue Leaflet, and Stadia Maps Free Starter Standard Professional Every web app benefits from a little geospatial intelligence. If you found this tutorial, you probably already know this. You can use Stadia Maps with Leaflet and Vue to add just the pop your dashboard or user experience needs—with an interactive map. This tutorial will show you how to build a simple map integration for your [Vue 3](https://vuejs.org) app using [Leaflet](https://leafletjs.com) and Stadia Maps. After you're done with this tutorial, you'll be able to: - Create a map in Vue 3 - Add layers to the map - Visualize a simple data set with markers on the map If all goes well, you'll get something that looks like this: For local development on a web server at `localhost` or `127.0.0.1`, you can get started without any API keys or domain setup! For mobile, backend, and non-local web development, you'll need either domain auth or an API key. If you don't already have a Stadia Maps account, [sign up for a free](https://client.stadiamaps.com/signup/) to get started. Domain-based authentication Domain-based authentication is the easiest form of authentication for production web apps. No additional application code is required, and you don't need to worry about anyone scraping your API keys. We recommend this for most browser-based applications. 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). 1. Click "Manage Properties." 1. Under "Authentication Configuration," click the button to add your domain. API key authentication ### Authenticating requests via API key You can authenticate your requests by adding an API key to the query string or HTTP header. Example URL with an API key placeholder ``` https://api.stadiamaps.com/tz/lookup/v1?lat=59.43696&lng=24.75357&api_key=YOUR-API-KEY ``` Example Authorization header with an API key placeholder ``` Authorization: Stadia-Auth YOUR-API-KEY ``` The simplest is to add a query string parameter `api_key=YOUR-API-KEY` to your request URL. For example, to access the `/tz/lookup` API endpoint, your request URL might look like this. You can also use an `Authorization` HTTP header instead of a query string as shown below. Don't forget the `Stadia-Auth` prefix! ### How to get an API key Don't have an API key yet? Follow these easy steps! 1. Sign in to the [client dashboard](https://client.stadiamaps.com/dashboard/). (If you don't have an account yet, sign up for free; no credit card required!) 1. Click "Manage Properties." 1. If you have more than one property (ex: for several websites or apps), make sure you have selected the correct property from the dropdown at the top of the page. 1. Under "Authentication Configuration," you can generate, view or revoke your API key. #### Video: How to generate your API key Demo Code You can clone the full code for this tutorial from [GitHub](https://github.com/stadiamaps/vue-3-leaflet-demo/) and follow along to save typing. ## Create a Vue 3 App If you don't already have a Vue app, it's easy to [create one](https://vuejs.org/guide/quick-start.html#creating-a-vue-application). Run the following command and follow the prompts: ``` npm init vue@latest cd npm install ``` ### Fix Vue 3 & Leaflet Attribution Display The default Vue 3 app ships with styles that aren't compatible with Leaflet, mostly affecting how the attribution and other controls are displayed. You'll want to remove those before you proceed. The simplest way to do this is to remove this CSS import in `src/main.js`: src/main.js ``` - import './assets/main.css' ``` Add the styles back Later, you'll probably want to go back and re-enable `main.css`. When you do that, be sure to remove the `display: grid` from `#app` to prevent conflicts with Leaflet. ## Install Dependencies You'll be using Leaflet and [Vue Leaflet](https://github.com/vue-leaflet/vue-leaflet), a Leaflet-wrapper for Vue for the map integration. Assuming you're in the project directory, run the following: ``` npm install --save leaflet @vue-leaflet/vue-leaflet ``` ## Start the Local Server You can use the `localhost` development web server (via `npm dev`) to get started developing your own app and following this tutorial right away. No account required! ``` npm dev ``` ## Download Data To give you a taste of the power of Leaflet and Vue, you'll need some data to download! We've already created a JSON file of all the arcades in Japan, which you can download and freely use in your project. [Download JSON](https://github.com/stadiamaps/vue-3-leaflet-demo/raw/main/leaflet/src/arcades.json) ## Create Map Page Before you can create the map, you'll need to add and remove some basic boilerplate in your new Vue app. First, remove the `
` and `` components from the `src/App.vue` file. (You should have an empty page now.) Next, update the following the ` ``` ## Add the Map Now you're ready to add your map to the page. In Vue Leaflet, you do this with the `` component. The primary map component takes a few parameters (you'll set `zoom` and `center` which controls what part of the world the map starts at). Once you have a map, you'll need a base layer, which you'll add with the `` component. Tip Check out the [library](../../themes/) for more raster map styles. You can add both by updating the template with the following code. Your entire `