Using ngrok to develop locally for Slack

By Claudio Medina

Creating apps and integrations for Slack is super easy. You can have webhooks or slash commands working in no time!

But wouldn't it be great if development could be simplified even more by allowing you to test your requests directly from your machine without constantly redeploying your work to a hosting platform/webserver?

Enter ngrok. This handy tool lets you set up a secure tunnel to your localhost, which is a fancy way of saying it opens access to your local app from the internet.

From the internet

This is what we'll do in this tutorial:

  • Download and setup ngrok on Mac.
  • Set up a simple HTTP server with node.js.
  • Build a Slack APP.
  • Create a slash command that sends a request to your new ngrok address and a simple message back to Slack.

By the end of this tutorial you'll be comfortable creating, working and running Slack apps locally before putting your app out there.

Setting up Ngrok

Step 1: Download ngrok

Go to and download the version that corresponds to your platform. In our case, we'll be downloading the Mac OS X 64-bit version.

Step 2: Install ngrok

Installing ngrok really only consists of extracting the file. Depending on how you want to run the app, you need to pay attention to where you extract the file:

a) You can extract ngrok into the folder of your preference and run ngrok from there.


b) (Recommended) Extract ngrok on your system's $PATH directory. The advantage of going with this option is that you'll be able to run ngrok from any path on the command line.

To get your system's $PATH simply type from the Terminal:

echo $PATH

In most cases this is usually:


Step 3: Tunnel your server

It's time to run ngrok and let the magic happen.

If you went for option A on Step 2, fire up a Terminal window, navigate to the directory where you unzipped ngrok and start it by telling it which port we want to expose to the public internet. To do this,type:

./ngrok http 4390

If ngrok is on your $PATH, you can simply type the following from any directory:

ngrok http 4390

If all goes well you should see the following:

ngrok running

The Online is a good sign! It means the tunnel is working and your app is now accessible at that particular 4390 port.

The address to access it from the internet would be the one next to Forwarding, with domain. In my case:

Finally, one of ngrok's neatest features is a UI to inspect requests. Let's access it by following the Web Interface URL

ngrok's UI

If we open up the Web Interface, we'll see that there are no requests since we haven't made any requests to our new ngrok address. Let's just click on the first HTTP url there to make a simple GET request from our browser.

ngrok GET attempt

Mmm... something has gone awry. Fear not.

While we've tunneled our app to the internet through that port &mash; we really don't have any app running yet! We'll need to create a web service that points to that port.

Step 4: Create a simple HTTP server

Let's set up a simple web server to processes all incoming HTTP requests.

For this part you'll need a code editor such as Sublime Text or Brackets. We'll be using Node.js to develop our app, so you'll need to make sure you've installed it on your machine as well.

Now create an empty folder for your project, let's name it slackapp. Create an index.js file inside that folder and open it up in your editor. Write down the following code. I've commented it so you can understand what's going on with each line:

// First we need to import the HTTP module. This module contains all the logic for dealing with HTTP requests.
var http = require('http');

// We define the port we want to listen to. Logically this has to be the same port than we specified on ngrok.
const PORT=4390;

// We create a function which handles any requests and sends a simple response
function handleRequest(request, response){
  response.end('Ngrok is working! -  Path Hit: ' + request.url);

// We create the web server object calling the createServer function. Passing our request function onto createServer guarantees the function is called once for every HTTP request that's made against the server
var server = http.createServer(handleRequest);

// Finally we start the server
server.listen(PORT, function(){
  // Callback triggered when server is successfully listening. Hurray!
  console.log("Server listening on: http://localhost:%s", PORT);

To run the app type the following from your slackapp directory using the Terminal:

sudo node index.js

If everything goes well, the following should be printed on your console:

Server listening on:

Now try visiting your ngrok address once more and you should be pleasantly surprised with a Ngrok is working! message. Well done!

Creating a Slack app and testing it locally with ngrok

Now that your local server is exposed to the internet, let's create a simple app with a slash command that gets a message from your server to confirm it's operational.

First, we'll need to modify our script so it can interact correctly with Slack. To keep our code short and sweet, we'll use a couple of essential third-party modules: express and request.

Express is a web application framework that allows us to set up a simple web server. It makes it easy to set up the routing logic we need for the requests we'll receive from Slack.

request is a convenient module to make HTTP calls. We'll use it to interact with Slack's web API.

Step 1: Create your Slack App

Let's go through a few simple steps to create an app from the Slack side. It's important to note that the app will remain private — submitting an app to the App Directory is an entirely different process.

Creating an app will provide us with the Client ID and Secret we need to input in our script on the second step and it's where we'll input our different ngrok endpoints.

  • Go to
  • Click on Create new App on the top-right hand-side.
  • Select the team you'd like the app to be associated as its creator and fill all remaining fields as shown below. You can change the description if you wish to. For now we'll leave the links to support and installation instructions blank as we're just using this app for testing purposes.
  • In the redirect URI field, paste your ngrok forwarding address and add the /oauth endpoint at the end of the address that we opened up in our script. In this example it would look something like this:
  • Click on Create App towards the bottom.

Create app

  • Now let's bundle a slash command with our app. Click on Slash Commands on the left menu -> Create New Command and fill the form as indicated below — just make sure that the Request URL matches your ngrok route and this time is pointing to the /command endpoint.

Configuring ngrok

  • We need to get one final piece of information for our app. Click on Basic Info on the left menu, copy your Client ID and Client Secret, and pass them as the corresponding variables on our script next.

Step 2: Refactor our script to work with Slack

// Import express and request modules
var express = require('express');
var request = require('request');

// Store our app's ID and Secret. These we got from Step 1. 
// For this tutorial, we'll keep your API credentials right here. But for an actual app, you'll want to  store them securely in environment variables. 
var clientId = '123456789.123456789';
var clientSecret = '11111a2222b3333c44444e';

// Instantiates Express and assigns our app variable to it
var app = express();

// Again, we define a port we want to listen to
const PORT=4390;

// Lets start our server
app.listen(PORT, function () {
    //Callback triggered when server is successfully listening. Hurray!
    console.log("Example app listening on port " + PORT);

// This route handles GET requests to our root ngrok address and responds with the same "Ngrok is working message" we used before
app.get('/', function(req, res) {
    res.send('Ngrok is working! Path Hit: ' + req.url);

// This route handles get request to a /oauth endpoint. We'll use this endpoint for handling the logic of the Slack oAuth process behind our app.
app.get('/oauth', function(req, res) {
    // When a user authorizes an app, a code query parameter is passed on the oAuth endpoint. If that code is not there, we respond with an error message
    if (!req.query.code) {
        res.send({"Error": "Looks like we're not getting code."});
        console.log("Looks like we're not getting code.");
    } else {
        // If it's there...

        // We'll do a GET call to Slack's `oauth.access` endpoint, passing our app's client ID, client secret, and the code we just got as query parameters.
            url: '', //URL to hit
            qs: {code: req.query.code, client_id: clientId, client_secret: clientSecret}, //Query string data
            method: 'GET', //Specify the method

        }, function (error, response, body) {
            if (error) {
            } else {


// Route the endpoint that our slash command will point to and send back a simple response to indicate that ngrok is working'/command', function(req, res) {
    res.send('Your ngrok tunnel is up and running!');

Do not upload this file to a public GitHub repository until you relocate variables such as the Client ID and Secret to environment variables. Keep your Client Secret safe!

Step 3: Engage!

Run the node script once more. Before we can run the slash command, we'll need to authenticate against our app to add it to our team. There's an easy way to generate the authentication link.

Simply go to, scroll down to the **Add the Slack button **section where you can find a handy generator for a button that would allow anyone to add your new app. Make sure the right app is selected on the generator and that you're requesting the commands scope, which is necessary to add our bundled slash command:

Add to Slack flow

Click on the Add to Slack button to go through the OAuth process and add the app to the team of your preference (it doesn't have to be the team used to create the app).

If all goes well, you should be able to send the /ngrok command from any channel on the team and will invoke the following response:

All that ends well

Well done — you've created a app that's actually running from your local server. You could just modify the response above, save the file, run your node process once more and when using your slash command the changes would be immediately reflected. Neat!

Now there's nothing stopping you from building more complex apps and use your new local development environment to test features like message buttons, using an ngrok route as your message action URI instead without any hassles. Try it out and experiment.

Related documentation