Getting Started

In this tutorial, we will walk you through the process of adding Extend to an existing, if simple, application. Our application is called Zero CRM and is a basic CRM application.

Testing the Initial Version

To get started, first clone the repository here: (Another option is to download the zip file from here). The initial application may be found in the before subdirectory. This sample application is written in Node.js, so if you haven’t installed Node, you’ll want to do that first. As this guide will also walk you through the entire process, you are welcome to just read and skip working with the code.

Once cloned, be sure to run npm i to get all the dependencies. (Again, remember to start in the before directory.) You can then start the application by using npm run start. You will be dropped immediately in the “Add New Lead” interface. Fill in anything you want here and click the “Create Lead” button. This will fire off an Ajax request back to the server and then render the response:

In the response, you’ll notice that a “Created” value has been added. This was done by the server simply to demonstrate that, typically, the server would do something with the data, like persist it.

There’s one more feature of this application and you can find it on the Settings page. The application wanted to allow users basic customization and it did this through a pretty common method - webhooks.

Webhooks work by asking the end user to set up their own server, or serverless function, and respond to a call from the application. It’s a common way for a service to allow for customizations. In this case, the application will be sending data about the lead and the webhook is responsible for doing something with the data and optionally returning a modified result. Another example would be simply sending you an email to let you know a new lead was created. To help illustrate this, you’ll see a default webhook URL provided. You’ll notice the default webhook URL is on the same local Node.js server. This is just a hack to keep things simple. Normally it would be one some other server. In this case, it will run a basic route that checks the value of the lead:'/webhook', (req, res) => {
	let lead = req.body;

	if(lead.value > 1000) = true;

The customization basically adds a VIP flag for high value leads. You can see this yourself if you go back to to the Lead form and add a new one with a high value:

Here’s the route that handles accepting new leads:'/api/leads',  (req, res) => {
	let data = req.body;
	// this is where - normally - a process of some sort would persist the value
	// data.created is simply demonstrating a server-side change
	data.created = new Date();

	if(webhookUrl != '') {

		let options = {

		request(options, (error, response, body) => {
			if(error) throw new Error(error);

	} else {

webhookUrl is a global variable just persisted in RAM. If you wish, you can actually build a real webhook, replace the URL, and try it out yourself.

Adding in Extend

Now we’re going to use Extend to enable users to write custom logic inline rather than needing to implement a webhook. If you want to skip ahead to the end, you can find the final version of the application in the after subdirectory. Don’t forget to run npm i inside the folder to add the necessary dependencies.

To begin working with Extend, you’ll first need to create a developer account. Point your browser at and you’ll be prompted to login:

Extend's home page

After you’ve logged in, you’ll be presented with a page with your keys for testing Extend:

Extend keys

For now, you only need to make note of two values - the container and token. Keep them handy as we’ll be using them in a moment.

Alright, so how do we add Extend to the application?

The first decision you will make is figuring out your “extension points”, or where you will allow for customizations. Luckily we’ve already done that. We’ve got a settings page that uses a webhook to customize the “New Lead” process.

Once we’ve figured that out, we need to make two changes to enable Extend for this customization. First, we have to add the editor. This is a hosted editor your users will work with to write their customization. The second change is to make use of their endpoint when a new lead is created. Our backend code is already making a network request to a webhook so this won’t be a big change. Let’s get started.

Setting up the Keys

Let’s begin by getting our keys recognized in the application. We’re making use of the dotenv package which makes storing and using “secret” values like our keys easy. Start by adding a new file to the root of the application called .env.


Obviously, you will want to replace the values above with the keys you got after logging in.

Starter Plan Users

If you are using the Extend Starter plan, your .env file will include one additional value:


The Starter plan try page also refers to a “container prefix” which each container name must start with. As a Starter plan user, you have access to a limited amount of containers. In addition to the 5 containers for production, you also have one dedicated dev container which you can use for running this sample. Copy the the dev container value from the try page to the EXTEND_CONTAINER setting.

Finally, the token provided to you is the master token for management of your Extend subscription and not for direct use by the application. To continue, you’ll need to first create a tenant token for you dev container. You can use Curl to create an appropriate key:

curl -X POST -H "Authorization: Bearer MYTOKENHERE" -H "Content-Type: application/json" --data '{"ten":"CONTAINER"}'

In the sample command above, MYTOKENHERE is your token. CONTAINER is the dev container you used previously. Take the result of this call and use that in the EXTEND_TOKEN setting.

We’re going to use these keys when displaying the editor and when invoking the extension, so we’ll load it in the routes/index.js file. Open it up and add this to the top:


This will read in the .env file you created and set the values in the process.env scope. Let’s use them now:

const extendContainer = process.env.EXTEND_CONTAINER;
let extendHost = '';
let extendURL = `https://${extendContainer}`;
let extendToken = process.env.EXTEND_TOKEN;

Now we’ll add the logic to handle if the host has been overridden.

if(process.env.EXTEND_HOST) {
	extendHost = process.env.EXTEND_HOST;
	extendURL = extendHost.replace('https://', `https://${extendContainer}.`)+'/';

This code sets up two local variables for each key and defines the extension URL based on the container value.

Adding the Editor

Now let’s add the Extend editor. While still in the routes/index.js file, scroll down to the /settings route and modify it like so:

app.get('/settings', (req, res) => {
	res.render('settings', { 

All we’re doing here is passing the values from our keys to the view. Let’s see how these are used. Open up views/settings.handlebars. Modify it so it looks like the code below:

<h2>Add New Lead</h2>

<div id="extend-editor" style="height: 600px; width: 100%"></div>
ExtendEditor.create(document.getElementById('extend-editor'), {
	hostUrl: '{{host}}',
	webtaskContainer: '{{container}}',
	token: '{{token}}',
	webtaskName: 'saveLead',
	createIfNotExists: true

Adding the Extend editor can be done quickly. You add a div that will be replaced by the editor and then drop in the code. There is a large set of customizations you can do to the editor but the defaults are fine for us. There are two things to take note of here. First, the webtaskName value gives a unique name to the extension. While you can name this whatever you want, it makes sense to give it a name that represents the customization or extension it is working with. Secondly, note that the keys passed to the route are used in the code so that the editor can act on your behalf.

Before we use the editor, we need to load the JavaScript file that lets the ExtendEditor API work. In views/layouts/main.handlebars, add this script tag in the head block:

<script src=""></script>

At this point, you should be able to test the editor. Run npm run start and go to the settings page.

Look at that beautiful editor. You’ve got basically a miniature IDE right within the browser. Of course, you don’t have to use this. You can provide your users a CLI path to building their extensions as well and they can use desktop editors, but this is certainly incredibly convenient. They don’t have to create a file, set up a server, or anything else. They can immediately begin writing code to add their customization.

The default code in the editor (which can be customized as well!) is a basic “hello world”, so let’s modify it to mimic the functionality from the previous webhook.

module.exports = function(context, cb) {
	var lead = context.body;
	if(lead.value > 1000) = true;
	cb(null, { lead:lead });

The value of the lead will exist in the context.body property so we make a quick copy just to make the code a bit more readable. We then do our logic (and feel free to modify this to your liking) and then return the lead with the callback provided in the cb argument.

Once done, be sure to click the floppy save icon to persist your change. (Or use CTRL/CMD+S like any proper editor!)

Calling the Extension

The next change is even simpler. The application was already calling out to a webhook to run the user’s customization. Now we will change the code to hit the Extend endpoint for their code instead. Open up routes/index.js again and replace the /api/leads with this updated version:'/api/leads',  (req, res) => {
	let data = req.body;
	// this is where - normally - a process of some sort would persist the value
	// data.created is simply demonstrating a server-side change
	data.created = new Date();

	let options = {
		url:extendURL +'saveLead',
		headers:{'Authorization':`Bearer ${extendToken}`},

	request(options, (error, response, body) => {
		if(error) throw new Error(error);


Basically, all we’ve done here is change the URL and add authorization information to the header. The URL is based on the value created earlier (which itself was based on your keys) and adds the name of the extension. This needs to match the webtaskName value used in the editor. Note that the lead value in data is posted to the endpoint as JSON data.

Save your work, restart the server, and test out your change by creating a new lead.

Testing and Logging

As we mentioned above, the Extend editor is incredibly powerful and customizable. Let’s look at just two of those features, but two of which may be really useful to you when you are just beginning.

The first is the “Show Logs” button:

Indicates which button shows logs

Clicking it opens a panel at the bottom:

Log panel

Make note of the two icons on the right. You will most likely always make use of autoscroll and the trash can will clear up the current output. Quickly modify the extension code to add some logging:

module.exports = function(context, cb) {
	var lead = context.body;
	console.log('lead', JSON.stringify(lead));
	if(lead.value > 1000) = true;
	cb(null, { lead:lead });

Save the extension and then open up the “Leads” link in a new tab. Enter some values, submit, and you’ll see the log panel update:

Log panel updates

Another useful feature is the “Runner”:

The Runner

Clicking this button opens a powerful testing utility that will perform network calls against the endpoint. To test, open the runner up and change the method type to POST. Under Body, set the content type to application/json and enter a test value.

Setting up test input for the Runner

Click run and you’ll see the output of your extension. You can also keep that Logs panel open as well to see any debugging you may have added.

The Runner result

Next Steps

Congratulations! You’ve just built your first application with Extend. Here are some next steps.

  • Learn more about the Extend platform by reading out Developer Guide.
  • Check out the specifics on the Extend Editor.
  • Join our Slack community to talk with other developers and Extend team members.
  • Check out our blog for interesting demos and examples of what you can do with Extend.