DEV Community

Cover image for How to Get a Route and Turn-by-Turn Directions with the Geoapify Routing API
Casey Rivers for Geoapify Maps API

Posted on

How to Get a Route and Turn-by-Turn Directions with the Geoapify Routing API

Some time ago, we published a full-featured example that shows how to build printable route directions using the Geoapify Routing API:

👉 Printable route directions example

The example combines multiple features in one project: route calculation, turn-by-turn instructions, static maps, elevation profiles, and a print-friendly layout. This makes it useful as a reference, but not easy to understand or reuse piece by piece.

Instead of covering everything at once, we are breaking that example into a series of focused tutorials. Each article explains one part of the solution and the data behind it, using plain JavaScript and minimal UI.

This is the first tutorial in the series. It focuses on the basics:

  • requesting a route from the Geoapify Routing API
  • understanding the routing response structure
  • extracting turn-by-turn navigation instructions
  • Try it in the live demo: View on CodePen

Later tutorials will reuse this foundation to add maps, previews, elevation data, and printable layouts.


Table of Contents

  1. What are Routing Directions and how to get them
  2. Build the Routing API Request
  3. Fetch and Parse the Response
  4. Display Route Summary
  5. Show Turn-by-Turn Directions
  6. Explore the Demo
  7. Summary
  8. FAQ

Routing directions: what they are and how the API provides them

Routing directions are the step-by-step instructions that guide a user along a route. They are the human-readable part of navigation, not just a line on a map.

Typical directions look like:

  • “Head north on Baker Street”
  • “In 350 m, turn right onto Oxford Street”
  • “Continue for 1.2 km”
  • “You have arrived at your destination”

These instructions are used in navigation panels, delivery apps, and printable route sheets where users need clear guidance from point A to point B.

When a route is calculated with the Geoapify Routing API, the response already contains these routing directions as structured steps, including distance, duration, and instruction text.

In this tutorial, we focus on obtaining this data and understanding where routing directions are located in the API response. In later parts of the series, we will show how to display, format, and visualize them in different ways.

Step 1: Build the Routing API Request

The Geoapify Routing API calculates routes between waypoints. You provide coordinates as latitude/longitude pairs, choose a travel mode, and request details like turn-by-turn instructions.

Define waypoints and parameters

Start by setting up the API key and waypoints:

const apiKey = "YOUR_API_KEY";

// Waypoints: Munich to Berlin
// Format: lat,lon|lat,lon|...
const waypoints = "48.1351,11.5820|52.5200,13.4050";
Enter fullscreen mode Exit fullscreen mode

🔑 API Key: Please sign up at geoapify.com and generate your own API key.

Build the request URL

Construct the full API request with waypoints, mode, and details:

const routingUrl = `https://api.geoapify.com/v1/routing?waypoints=${waypoints}&mode=drive&details=instruction_details&apiKey=${apiKey}`;
Enter fullscreen mode Exit fullscreen mode

Key parameters

Parameter Description Example
waypoints Pipe-separated lat,lon pairs 48.13,11.58 | 52.52,13.40
mode Travel mode drive, walk, bicycle, truck
details Include extra data instruction_details for turn-by-turn
apiKey Your Geoapify API key Get one at myprojects.geoapify.com

The details=instruction_details parameter tells the API to include turn-by-turn navigation instructions in the response.

📘 API Documentation: Learn more about request parameters in the Routing API docs.


Step 2: Fetch and Parse the Response

Now we'll request the route from the API and extract the route data.

Make the API request

async function fetchRoute() {
  try {
    const response = await fetch(routingUrl);

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();

    // Check if we got a valid route
    if (!data.features || data.features.length === 0) {
      throw new Error("No route found");
    }

    // The route is the first feature in the GeoJSON response
    const route = data.features[0];

    // Display the results
    displaySummary(route);
    displayDirections(route);
    displayRawResponse(data);

  } catch (error) {
    console.error("Error fetching route:", error);
  }
}
Enter fullscreen mode Exit fullscreen mode

The API returns a GeoJSON FeatureCollection. The route geometry and all metadata are in the first feature.

Response structure

The response contains everything you need for navigation:

{
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature",
    "properties": {
      "mode": "drive",
      "waypoints": [
        { "location": [11.582, 48.1351], "original_index": 0 },
        { "location": [13.405, 52.52], "original_index": 1 }
      ],
      "units": "metric",
      "details": ["instruction_details"],
      "distance": 585050,           // Total distance in meters
      "distance_units": "meters",
      "time": 20454.257,            // Total time in seconds
      "legs": [...]                 // Route segments with steps
    },
    "geometry": {
      "type": "MultiLineString",
      "coordinates": [...]          // Route line coordinates
    }
  }]
}
Enter fullscreen mode Exit fullscreen mode

The route data is in features[0].properties:

Field Description
distance Total route distance in meters
distance_units Units for distance (meters or miles)
time Estimated travel time in seconds
legs Array of route segments (one per waypoint pair)
waypoints Waypoints with coordinates and original order
mode Travel mode used (drive, walk, bicycle, etc.)
units Measurement system (metric or imperial)

ℹ️ Units and language

Distance values are returned in meters and time in seconds by default. The measurement system depends on the units parameter (metric or imperial).

Turn-by-turn instruction text is localized. Use the lang parameter in the request (for example, lang=de) to receive instructions in the required language.


Step 3: Display Route Summary

Extract and format the route summary data for display.

Format distance and time

function displaySummary(route) {
  const props = route.properties;

  // Extract key information
  const distance = props.distance; // in meters
  const time = props.time; // in seconds
  const legs = props.legs ? props.legs.length : 0;

  // Format distance
  const distanceKm = (distance / 1000).toFixed(1);
  const distanceMiles = (distance / 1609.34).toFixed(1);

  // Format time
  const hours = Math.floor(time / 3600);
  const minutes = Math.floor((time % 3600) / 60);
  const timeFormatted = hours > 0 ? `${hours}h ${minutes}min` : `${minutes}min`;

  // Display in UI (HTML generation omitted for brevity)
}
Enter fullscreen mode Exit fullscreen mode

The demo shows total distance in both kilometers and miles, estimated travel time, number of route legs, and travel mode.

Screenshot showing route summary section with total distance in km and miles, estimated travel time, number of route legs, and travel mode

The route summary displays total distance, travel time, and route details extracted from the API response.


Step 4: Show Turn-by-Turn Directions

Each route contains legs (segments between waypoints), and each leg contains steps (individual maneuvers with instructions).

Extract and display steps

function displayDirections(route) {
  const props = route.properties;

  if (!props.legs || props.legs.length === 0) {
    return;
  }

  let stepNumber = 1;

  // Loop through each leg (segment between waypoints)
  props.legs.forEach((leg) => {
    if (!leg.steps) return;

    // Loop through each step in the leg
    leg.steps.forEach((step) => {
      const instruction = step.instruction;
      const distance = step.distance;
      const time = step.time;

      // Format step distance
      let distanceText = "";
      if (distance >= 1000) {
        distanceText = `${(distance / 1000).toFixed(1)} km`;
      } else {
        distanceText = `${Math.round(distance)} m`;
      }

      // Format step time
      let timeText = "";
      if (time >= 60) {
        timeText = `${Math.round(time / 60)} min`;
      } else {
        timeText = `${Math.round(time)} sec`;
      }

      // Display step (HTML generation omitted)
      console.log(`${stepNumber}. ${instruction.text} - ${distanceText}`);
      stepNumber++;
    });
  });
}
Enter fullscreen mode Exit fullscreen mode

Each step includes:

Field Description
instruction.text Human-readable turn instruction
instruction.type Maneuver type (e.g., TurnRight, TurnLeft)
distance Distance for this step in meters
time Time estimate for this step in seconds

💡 Implementation note

Use instruction.type for logic and UI decisions (icons, grouping, behavior). These values are stable and language-independent.

The instruction.text field is localized and intended for display only. Do not rely on it for application logic.

Instruction types

The instruction.type field tells you what kind of maneuver it is. Here are some common types:

Type Description
StartAt, StartAtRight, StartAtLeft Starting point
DestinationReached, DestinationReachedRight, DestinationReachedLeft Arrival at destination
Straight Continue straight
Right, SlightRight, SharpRight Right turns (varying angles)
Left, SlightLeft, SharpLeft Left turns (varying angles)
Roundabout Enter roundabout
ExitRight, ExitLeft Take an exit
Merge, MergeRight, MergeLeft Merge onto another road
FerryEnter, FerryExit Ferry crossing

You can use these types to display appropriate turn icons or customize the UI presentation.

📘 Full list: See all instruction types in the Routing API documentation.

Screenshot showing turn-by-turn directions list with numbered steps, instruction text, distance, and time for each maneuver

Turn-by-turn directions list each step with instruction text, distance, and estimated time.


Step 5: Explore the Demo

This demo intentionally avoids map rendering. Its purpose is to show how routing data and turn-by-turn directions can be requested, parsed, and displayed without any mapping library.

The live CodePen demo ties everything together in a working example.

What the demo shows

  1. Fetch Route - Click the button to request a route between Munich and Berlin
  2. Route Summary - Total distance, time, and number of legs
  3. Turn-by-Turn Directions - Each step with instruction text, distance, and time
  4. Raw API Response - Simplified view of the JSON structure

Experiment with the code

  • Change the waypoints variable to different cities
  • Update the mode parameter to walk, bicycle, or truck
  • Add more waypoints using pipe-separated coordinates (e.g., "lat1,lon1|lat2,lon2|lat3,lon3")


Summary

We’ve built a simple but complete routing workflow that focuses on working with routing data, not UI frameworks:

  1. Build a routing request by defining waypoints, travel mode, and required details
  2. Request routing data and parse the GeoJSON response
  3. Extract route-level properties such as total distance and travel time
  4. Process turn-by-turn directions as structured steps that can be rendered, logged, or stored

This approach gives you a reusable foundation for:

  • navigation panels and instruction lists,
  • delivery and field-service applications,
  • server-side route processing and report generation.

An important practical point: treat routing directions as data, not as final UI. Keep them separate from presentation logic so you can reuse the same response for web, mobile, or printable outputs without recalculating the route.

Useful links:


FAQ

Q: How many waypoints can I include in a route?

A: The Routing API supports multiple waypoints. For complex routes with many stops, consider the Route Planner API which optimizes the order of visits.

Q: What travel modes are available?

A: The API supports drive, walk, bicycle, bus, truck, scooter, motorcycle, and specialized modes. Each mode uses appropriate roads and calculates realistic travel times. Check the Routing API documentation for the complete list.

Q: Can I get elevation data with the route?

A: Yes. Add details=elevation to the request. The response will include elevation_range data in each leg.

Q: How do I avoid highways or tolls?

A: Add the avoid parameter: avoid=highways or avoid=tolls. You can combine multiple: avoid=highways|tolls|ferries.

Q: Can I get the route in a different language?

A: Yes, add the lang parameter (e.g., lang=de for German). The instruction text will be localized.


Try It Now

👉 Open the Live Demo

Please sign up at geoapify.com and generate your own API key to start building route-based applications.

Top comments (0)