Tile Server

This endpoint returns raster tiles (images) of our time series weather data. The tile endpoint can be used with a mapping client, such as Leaflet.js or Mapbox, to make an interactive world map.

Get Tile PNG

This endpoint allows you to get PNG images of raster data for a specific area of the globe. The area is determined using the OSM Tile format based on the desired zoom level. More details on the specific tile format and specification can be found on the OSM website located at https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames. Most mapping clients will accept a tile url with the parameters for zoom, x, & y formatted as: {z}/{x}/{y}.png
Path Parameters
The ID of the model for which you want to display tile data from.
The desired zoom level to be used when cutting tiles.
The x coordinate index of the tile to be returned.
The y coordinate index of the tile to be returned.
Query Parameters
A valid API token
A string describing the colormap to use within each tile. Defaults to 'jet'. See the additional information section for all of the available options.
A valid variable ID specifying the content of the data returned from a specific model. The variable must have an existing association with the given model parameter.
A string describing the point in time that the returned tile data is located at. The time string must be a valid ISO8601 formatted timestamp. For example YYYY-MM-DDThh-mm-ssTZD (where TZD is the time zone. Use Z for UTC). Additionally the API will only return tiles when the timestamp represents a whole hour (No minutes or seconds) and the given model/variable combination has data available at that time. Some models only have data available every 3 hours (T00, T03, ..., T21) so a tile request for 'T04:00:00' will return a 404 error. If not provided, the tiles will be generated from the most recently available data for that model and variable -- which may update at any time.
200: OK
Successfully returns image data
// Returns tile as PNG image
400: Bad Request
Necessary request parameters were either not included or were improperly formatted
{ "message": "Request must include 'timestamp' query parameter"}
404: Not Found
Requested model, variable, or timestamp (for that specific model) does not exist, or is not available.
{ "message": "Variable 'FakeVariable' does not exist" }
500: Internal Server Error
An error occurred in our backend while trying to return the requested tile.
{ "message": "Internal Server Error" }

Example Usage

The following HTML code uses Mapbox GL JS to display model data served by our Tile Server API. The page features a slider that allows you to select the desired time (anywhere from 24 hours in the past, to 6 hours in the future). You can run this demo either by visiting the file in a local browser or using the code pen featured below.

<!-- Simple example using mapbox-gl-js along with the Sofar tile api to create a map that shows data from a certain model/variable at various times-->
<!DOCTYPE html>
<meta charset="utf-8" />
<title>Sofar Tile Server Demo</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.9.1/mapbox-gl.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.25.3/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.9.1/mapbox-gl.css" rel="stylesheet" />
body { margin: 0; padding: 0; font-family: sans-serif; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
#model-info {
position: relative;
background-color: #eee;
margin: 5px;
padding: 5px;
display: inline-block;
#map-overlay {
position: relative;
margin: 5px;
padding: 5px;
display: inline-block;
<div id="map"></div>
<div id="model-info">
<b>Model:</b> <label id="model-name"></label> <br>
<b>Variable:</b> <label id="variable-name"></label> <br>
<div id="map-overlay">
<b>Inference Time:</b>
<label id="timestamp"></label>
<input id="slider" type="range" min="0" max="4" step="1" value="3" />
// link used to access the sofar api. The timestamp is appended on dynamically as the slider changes
// This particular demo accesses significant wave height data from the Sofar Wave Model
const modelName = "SofarOperationalWaveModel"
const variableName = "significantWaveHeight";
const cmap = "turbo";
const sofarApiToken = "383d59964809ca8c6438867e590f16";
// get closest available hour
const modelTimesEndpoint =
"https://api.sofarocean.com/marine-weather/v1/models/" +
modelName +
"/outputTimes?token=" +
sofarApiToken +
"&closest=" +
const linkPrefix =
"https://api.sofarocean.com/marine-weather/v1/models/" +
modelName +
+ cmap +
"&token=" +
sofarApiToken +
"&variableID=" +
variableName +
$.get( modelTimesEndpoint, function( data ) {
// upon loading a valid model time, use that as a starting point
const timestamp = moment(data.outputTimes[0]);
// Add 30 hours of available times to the slider. 1 day ago to 6 hours in the future
const dates = [];
const startDate = timestamp.subtract(1, "day");
for (let i = 0; i < 5; i++) {
dates.push(startDate.add(6, "hour").toISOString());
// update info box
document.getElementById("model-name").textContent = modelName;
document.getElementById("variable-name").textContent = variableName;
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9uc2VuIiwiYSI6IkR6UU9oMDQifQ.dymRIgqv-UV6oz0-HCFx1w'
let map = new mapboxgl.Map({
container: "map", // container id
style: "mapbox://styles/jonsen/ck8i301kh0cy31ipfi7y8j6bb",
center: [-74.5, 40], // starting position
zoom: 2, // starting zoom
// Function that updates the map data based on the current slider timestamp
function updateDate(newIndex) {
let currentTime = dates[newIndex];
document.getElementById("timestamp").textContent = currentTime;
let link = linkPrefix + currentTime;
map.addSource("sofar-tiles", {
type: "raster",
tiles: [link],
tileSize: 256,
attribution: "Sofar Ocean Technologies"
id: "sofar-tiles",
type: "raster",
source: "sofar-tiles",
minzoom: 0,
maxzoon: 10
map.on("load", function () {
// set to be the current time which has index 23
document.getElementById("slider").addEventListener("input", function (e) {
const dateIndex = parseInt(e.target.value, 10);
if (map.getLayer("sofar-tiles")) map.removeLayer("sofar-tiles");
if (map.getSource("sofar-tiles")) map.removeSource("sofar-tiles");

Additional Information

Colormap Options