npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-map-direction-with-custom-url

v2.0.2

Published

Secure Directions component for react-native-maps that hides Google Maps API Keys using a Backend Proxy to prevent DDoS attacks and quota draining.

Readme

react-native-map-direction-with-custom-url

npm Version License

Directions component for react-native-maps – Draw a route between two coordinates, powered by the Google Maps Directions API.

🛡️ Why use this instead of the standard library?

The standard react-native-maps-directions library requires you to embed your Google Maps API Key directly in your mobile app. This is a security risk as the key can be easily extracted, leading to unauthorized usage or DDoS attacks (exhausting your API quota).

This library innovates by introducing a "Secure Backend Proxy mode":

  • Hidden API Keys: Keep your Google Maps keys safe on your server.
  • Enhanced Security: Prevent DDoS attacks and unauthorized quota usage.
  • Backend Restrictions: Apply custom authentication, rate limiting, and business logic before calling Google.
  • Seamless Integration: Your app receives the same high-quality route data as if it called Google directly.

Installation

npm install react-native-map-direction-with-custom-url

or

yarn add react-native-map-direction-with-custom-url

Basic Usage

Mode 1 — Direct Google Maps API

Pass your Google Maps API key directly:

import MapViewDirections from 'react-native-map-direction-with-custom-url';

const origin = {latitude: 37.3318456, longitude: -122.0296002};
const destination = {latitude: 37.771707, longitude: -122.4053769};
const GOOGLE_MAPS_APIKEY = '…';

<MapView initialRegion={…}>
  <MapViewDirections
    origin={origin}
    destination={destination}
    apikey={GOOGLE_MAPS_APIKEY}
  />
</MapView>

Mode 2 — Secure Backend Proxy (Recommended)

Use this mode to protect your Google Maps API Key. Your app calls a backend endpoint (which you control), and your backend performs the actual Google Maps request. This prevents hackers from stealing your key and allows you to enforce backend-side security.

import MapViewDirections from 'react-native-map-direction-with-custom-url';

<MapView initialRegion={…}>
  <MapViewDirections
    origin={origin}
    destination={destination}
    useBackendApi={true}
    backendUrl="https://your-api.com/directions"
    backendAuthToken="YOUR_BACKEND_AUTH_TOKEN"
  />
</MapView>

Your backend must return a response in the Google Maps Directions API format:

{ "status": "OK", "routes": [...] }

The component also supports these wrapper formats from your backend:

{ "data": { "status": "OK", "routes": [...] } }
{ "getMapsDirectionsResponse": { "status": "OK", "routes": [...] } }

Once the directions between origin and destination have been fetched, a MapView.Polyline between the two will be drawn. Whenever either changes, new directions will be fetched and rendered.

Backend Implementation Guide

To use Mode 2, you need to set up a simple endpoint on your backend.

1. The Endpoint

Your backend should expose a POST endpoint (e.g., /api/directions) that accepts application/x-www-form-urlencoded data.

2. What the Backend calls

When your backend receives a request from the app, it should make a request to the Google Maps Directions API: GET https://maps.googleapis.com/maps/api/directions/json?origin=...&destination=...&key=YOUR_SECRET_API_KEY

3. Forwarding the Response

Your backend simply needs to forward the exact same JSON response it gets from Google back to the mobile app.

Backend Flow:

  1. App calls POST https://your-backend.com/directions with parameters.
  2. Backend calls GET https://maps.googleapis.com/maps/api/directions/json?... with your restricted API key stored safely in environment variables.
  3. Backend returns the JSON from Google to the App.
  4. (Optional) You can add logic to verify the backendAuthToken before calling Google.

Component API

Props

Required

| Prop | Type | Note | |---|---|---| | origin | LatLng or String | The origin location to start routing from. | | destination | LatLng or String | The destination location to start routing to. |

Mode 1 — Direct Google Maps

| Prop | Type | Default | Note | |---|---|---|---| | apikey | String | | Your Google Maps Directions API Key. Required when useBackendApi is false. |

Mode 2 — Backend Proxy

| Prop | Type | Default | Note | |---|---|---|---| | useBackendApi | boolean | false | Set to true to route requests through your own backend. | | backendUrl | String | | Your backend endpoint URL. Required when useBackendApi is true. Your backend must return Google Maps Directions API format. | | backendAuthToken | String | | Optional Bearer token sent in the Authorization header to authenticate with your backend. |

Shared Props

| Prop | Type | Default | Note | |---|---|---|---| | waypoints | [LatLng or String] | [] | Array of waypoints to use between origin and destination. | | language | String | "en" | The language to use when calculating directions. See here for more info. | | mode | String | "DRIVING" | Transportation mode. Allowed values: "DRIVING", "BICYCLING", "WALKING", "TRANSIT". | | resetOnChange | boolean | true | Set to false if you see the directions line glitching when recalculating. | | optimizeWaypoints | boolean | false | Let Google Maps re-order waypoints for the fastest route. | | splitWaypoints | boolean | false | Automatically split waypoints into multiple routes to bypass the 10-waypoint API limit. | | directionsServiceBaseUrl | string | (Google's) | Override the base URL of the Directions API. Usually not needed. | | region | String | | Region hint for string-based origin/destination to help Google Maps resolve the correct location. | | precision | String | "low" | Polyline detail level. "low" = smoothed overview path; "high" = full step-by-step path (may hit performance). | | timePrecision | String | "none" | Set to "now" to get real-time traffic info. | | channel | String | null | Channel parameter for Google Maps billing analytics. |

More props

Since the result rendered on screen is a MapView.Polyline component, all MapView.Polyline props – except for coordinates – are also accepted.

<MapViewDirections
  origin={origin}
  destination={destination}
  apikey={GOOGLE_MAPS_APIKEY}
  strokeWidth={3}
  strokeColor="hotpink"
/>

An extra note on origin and destination

The values can take several forms:

<MapViewDirections origin={{ latitude: 37.3317876, longitude: -122.0054812 }} destination="…" />
<MapViewDirections origin="37.3317876,-122.0054812" destination="…" />
<MapViewDirections origin="Apple Park Visitor Center" destination="…" />
<MapViewDirections origin="10600 N Tantau Ave, Cupertino, CA 95014, USA" destination="…" />
<MapViewDirections origin="place_id:ChIJW5i0tJC1j4ARoUGtkogTaUU" destination="…" />

Events/Callbacks

| Event Name | Returns | Notes | |---|---|---| | onStart | { origin, destination, waypoints: [] } | Called when routing has started. | | onReady | { distance: Number, duration: Number, coordinates: [], fare: Object, waypointOrder: [[]] } | Called when routing successfully finished. Distance in km, duration in minutes. | | onError | errorMessage | Called when routing has failed. |

Extended Example

import React, { Component } from 'react';
import { Dimensions, StyleSheet } from 'react-native';
import MapView from 'react-native-maps';
import MapViewDirections from 'react-native-map-direction-with-custom-url';

const { width, height } = Dimensions.get('window');
const ASPECT_RATIO = width / height;
const LATITUDE = 37.771707;
const LONGITUDE = -122.4053769;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

// Option A: Direct mode
const GOOGLE_MAPS_APIKEY = '…';

// Option B: Backend proxy mode
const BACKEND_URL = 'https://your-api.com/directions';
const BACKEND_AUTH_TOKEN = '…';

class Example extends Component {

  constructor(props) {
    super(props);
    this.state = {
      coordinates: [
        { latitude: 37.3317876, longitude: -122.0054812 },
        { latitude: 37.771707, longitude: -122.4053769 },
      ],
    };
    this.mapView = null;
  }

  onMapPress = (e) => {
    this.setState({
      coordinates: [...this.state.coordinates, e.nativeEvent.coordinate],
    });
  }

  render() {
    return (
      <MapView
        initialRegion={{
          latitude: LATITUDE,
          longitude: LONGITUDE,
          latitudeDelta: LATITUDE_DELTA,
          longitudeDelta: LONGITUDE_DELTA,
        }}
        style={StyleSheet.absoluteFill}
        ref={c => this.mapView = c}
        onPress={this.onMapPress}
      >
        {this.state.coordinates.map((coordinate, index) =>
          <MapView.Marker key={`coordinate_${index}`} coordinate={coordinate} />
        )}
        {(this.state.coordinates.length >= 2) && (
          <MapViewDirections
            origin={this.state.coordinates[0]}
            waypoints={(this.state.coordinates.length > 2) ? this.state.coordinates.slice(1, -1) : undefined}
            destination={this.state.coordinates[this.state.coordinates.length - 1]}
            // Direct mode:
            apikey={GOOGLE_MAPS_APIKEY}
            // OR Backend proxy mode:
            // useBackendApi={true}
            // backendUrl={BACKEND_URL}
            // backendAuthToken={BACKEND_AUTH_TOKEN}
            strokeWidth={3}
            strokeColor="hotpink"
            optimizeWaypoints={true}
            onStart={(params) => {
              console.log(`Started routing between "${params.origin}" and "${params.destination}"`);
            }}
            onReady={result => {
              console.log(`Distance: ${result.distance} km`);
              console.log(`Duration: ${result.duration} min.`);
              this.mapView.fitToCoordinates(result.coordinates, {
                edgePadding: {
                  right: (width / 20),
                  bottom: (height / 20),
                  left: (width / 20),
                  top: (height / 20),
                }
              });
            }}
            onError={(errorMessage) => {
              console.log('Routing error:', errorMessage);
            }}
          />
        )}
      </MapView>
    );
  }
}

export default Example;

Changelog

Please see CHANGELOG for more information on what has changed recently.

Credits

  • Dhruv Nagvadia (https://github.com/dhruv-nagvadia) — Backend proxy mode, API key restriction support
  • Bram(us) Van Damme (https://www.bram.us/) — Original library
  • All Contributors

License

The MIT License (MIT). Please see License File for more information.