How to Create an Elevation Profile for a Route

API or service
Routing API
Task
Route waypoints → distance and elevation chart
Examples
URLJavaScript
Difficulty
Intermediate
Time
12 min

Create an elevation profile for a route

You have walking, hiking, cycling, or driving waypoints and need to show how elevation changes along the route. Request elevation details from the Routing API, transform the returned distance-height pairs into chart points, and render them in your application.

Elevation describes the calculated route rather than a straight line between the waypoints. This matters on winding roads and trails where distance along the route is longer than direct distance.

Task flow: route waypoints → Routing API elevation details → distance and height points → elevation chart.

Request elevation data

This request calculates a hiking route in the Dolomites and adds elevation details:

https://api.geoapify.com/v1/routing?waypoints=46.556675,11.765165|46.549250,11.793963&mode=hike&details=elevation&format=json&apiKey=YOUR_API_KEY

Reduced response:

{
  "results": [
    {
      "distance": 3949,
      "time": 7607.256,
      "legs": [
        {
          "distance": 3949,
          "time": 7607.256,
          "elevation_range": [
            [0, 1613.5],
            [7.826, 1614.309],
            [13.134, 1614.857],
            [27.619, 1616.354],
            [33.24, 1616.784],
            [44.299, 1617.41]
          ]
        }
      ]
    }
  ]
}

Each elevation_range entry is [distance, elevation] in meters. The complete response contains 268 samples for this route; the example above is reduced to the first six.

The related elevation array contains heights aligned with route geometry points. Prefer elevation_range for a profile because it already pairs each height with distance traveled along the leg.

Prepare elevation chart points

For a route with multiple legs, distance in each leg starts from that leg’s origin. Add the lengths of previous legs to create one continuous x-axis.

function getElevationPoints(routingResponse) {
  const route = routingResponse.results[0];
  let distanceOffset = 0;

  return route.legs.flatMap(leg => {
    const points = leg.elevation_range.map(([distance, elevation]) => ({
      distance: distanceOffset + distance,
      elevation
    }));

    // The next leg starts after the current leg's full route distance.
    distanceOffset += leg.distance;
    return points;
  });
}

const points = getElevationPoints(routingResponse);

Keep the original meter values in application state. Convert distance to kilometers or miles only when formatting axis labels and tooltips.

Render the elevation profile

This small renderer creates an SVG line chart without a charting dependency. It expects the points array created in the previous step.

function renderElevationProfile(container, points) {
  if (!points.length) {
    container.textContent = "Elevation data is unavailable.";
    return;
  }

  const width = 640;
  const height = 240;
  const padding = 24;
  const maxDistance = Math.max(...points.map(point => point.distance));
  const distanceSpan = Math.max(maxDistance, 1);
  const elevations = points.map(point => point.elevation);
  const minElevation = Math.min(...elevations);
  const maxElevation = Math.max(...elevations);
  const elevationSpan = Math.max(maxElevation - minElevation, 1);

  const x = distance => padding + distance / distanceSpan * (width - 2 * padding);
  const y = elevation => height - padding
    - (elevation - minElevation) / elevationSpan * (height - 2 * padding);

  const path = points
    .map((point, index) => `${index ? "L" : "M"} ${x(point.distance)} ${y(point.elevation)}`)
    .join(" ");

  container.innerHTML = `
    <svg viewBox="0 0 ${width} ${height}" role="img" aria-labelledby="elevation-title">
      <title id="elevation-title">Route elevation profile</title>
      <path d="${path}" fill="none" stroke="#623aff" stroke-width="3" />
    </svg>`;
}

renderElevationProfile(document.querySelector("#elevation-profile"), points);

Give the chart container a visible size in CSS and provide textual minimum, maximum, distance, and ascent values near the visualization. The SVG title helps screen-reader users identify the chart, but it does not replace a useful text summary.