Unit 2 · Getting Started with Custom Apps

Testing your custom app

23 min read Updated May 19, 2026

Testing your custom app

Welcome to the Getting started with custom apps course.

If you have never built a custom app before or never thought about it, you’re in the right place!

In this course, you will explore and learn:

what custom apps are and the benefits of using them

an overview of the custom app elements and how they relate to HTTP calls

how to build your first custom app

Discover this amazing feature that Make offers! Note that everyone with a Make account can create custom apps. Yes, even with a free plan! Exciting, right?

Custom app structure

Now that you know how your custom app should work, have reviewed the API documentation, and tested your HTTP call in Postman, it’s time to start building it.

You’ll use the web interface for this, and the first step is understanding the app’s structure, including its components and tabs.

You can find the Custom Apps menu on the left side, where all your apps are

listed, and you can create new ones.

For now, let’s just explore the different components that make a custom app,

you’ll build the app later in the course. The app is made of different components that define its behavior.

To set up your first custom app, you will focus on the following components, which are the

minimum required to create a working app with one module:

Base: define the settings that are common and inherited by all the modules

Connections: configure the authentication settings to access the API and test that they are working properly

Modules: set up the individual modules of your app

To define the settings of your components, you use the tabs nested within them. You will explore these tabs in more detail when setting up the components.

Note that the same structure applies when using VS Code.

Giving instructions

Make has an engine that runs the custom apps (and all apps in Make).

To build your custom app, you need to interact with this engine, giving it instructions on which actions to take to make your app work.

To do this, you use JSONC (JSON with Comments) and IML (Integromat Markup Language) in the app builder. JSONC is a version of JSON that allows comments, unlike standard JSON. Comments can be single-line (//) or multi-line (/* */), just like in JavaScript. IML is a language developed by Make to enable the use of functions within components.

You use this to instruct the apps engine on the actions you want it to perform and to specify the parameters that the user will need to input.

Work through the images below to learn more.

You use specific keywords as directives to instruct the apps engine to perform specific actions. For example, if you want the apps engine to access a specific URL, you would use: “url”: “https://gotothispage.com”. You can find more information about the available directives at this link.

To make a request, you must specify at least a URL. The other directives are optional.

You can use JSONC to define parameters, which are values provided by the user of the app and used by the directives. Each parameter is defined by the settings that describe its properties. You can find the common parameter settings at this link.

Within the same component, you can access any parameter using the notation {{parameters.name}}, like for example {{parameters.apiKey}}. When writing JSONC, you can use various data types that are derived from standard JSON data types. You can find more information about the data types at this link.

These are the ones you’ll need for this course:

Getting started

Time to get your hands dirty and start building the Geocodify app.

Go to the Custom Apps menu and select + Create a new app. In the pop-up window you will need to fill in the app details. Let’s start by having a look at the information you will need to provide.

 

1/7 Name

Unique identifier for your custom app. It is an internal name and is not visible in the scenario builder. Check the Regex below the box to see the character requirements. 

2/7 Label

Name of the custom app in the scenario editor. It doesn’t have any character restriction, except for the maximum length of 128 characters. 

3/7 Description

[Optional]

Description of the custom app. 

4/7 Theme

Color of the app in the scenario editor. It is specified using a hex code. 

5/7 Language

Language of your app. This value is just for your information, Make doesn’t automatically translate the app. 

6/7 Audience

Where the app is available. Note that at the moment this parameter doesn’t have any effect. 

7/7 Logo

[Optional]

Logo of the app used in the scenario editor.

Before starting to fill in all the fields, let’s look at the logo requirements and make sure you have a logo for your app.

These are the logo requirements:

an image file in .png format

square dimensions: minimum 512 x 512 px and maximum 2048 x 2048 px

a maximum file size of 512 kB

Make processes the icon file by adjusting its colors. White or transparent areas in the logo will appear in the color set in the Theme field.

Black areas will be converted to full opacity and shown as white.

Colored or semi-transparent areas will be displayed in a shade between white and the Theme field color.

For this exercise, download the logo below.

If you want to create your own, you can use LunaPic to edit your photos for free.

geocodify-logo.png

Build it

If you haven’t done it yet, select + Create a new app in the Custom Apps menu. Complete the form with the relevant information as shown below:

Name: geocodify-app

Label: Geocodify

Description: Provides geocoding and access to a spatial database

Theme: #463f7f

Language: English

Audience: Global

App logo: Upload the image you downloaded before

Note that you can find the theme color by inspecting the Geocodify website and selecting the

hex code for the purple background on the landing page.

Click Save to create the app.

Learn it

To begin setting up the components, start with Connections, as the other components will use the Connections’ parameters. When building the Connections component, you will set up the form that appears when the user

clicks Create a connection. You will define the parameters the user has to input and how these are handled by the apps engine to verify the authentication parameters.

The Connections component sets up the details needed to authenticate with the API and ensures everything works when the user enters their credentials in the scenario editor.

It has three main jobs:

  1. Getting any relevant information from the user that adds the connection (credentials, API key, etc)

  2. Processing the authentication

  3. Checking if the authentication works by making a test API call

You set this up in the Communication tab, while the Parameters tab holds the information the user needs to provide.

Let’s have a look at the Connections component before setting it up. You don’t have to do anything at this point, but you can create a new connection if you want to follow along. When you click Create a new connection, Make presents you with a list of the most common

connection types with already filled in code that you can modify according to your needs.

For this exercise you will select API Key, but before doing so let’s explore the pre-filled in

code.

Work through the images below to learn more. The code in the Communication tab is divided into three sections:

  1. Request

  2. Response

  3. Log

The first part defines the HTTP request the app uses to validate the user’s credentials. This call happens when the user enters their credentials and clicks Create a Connection.

The usual way to validate credentials is to call an API endpoint that returns user details. If the API doesn’t provide this, you can use a generic endpoint to validate the credentials by making a GET request to ensure that the authentication is correct. The default HTTP method is GET, so you don’t need to specify it. Adding this validation call is a good practice to make sure the credentials are correct.

The second part contains directive on how to handle the response:

metadata: Stores the user details that are returned by the API call and displays them next to the connection in the Connections page, for ease of identification.

error: Contains instructions on the information that is displayed when an error occurs to help the user understand the issue. Lets you set the type of error and the message that will appear if the API request fails.

The third part contains instructions regarding the log and the information recorded in it: sanitize: specifies which information shouldn’t be recorded in the logs for security reasons.

The Parameters tab contains one parameter: apiKey. This is the information the user has to provide in the scenario.

Note that the parameter is used in the Communication tab using the notation {{parameters.name}}.

In the Communication tab you can also find:

Connected system: To define on-prem agents for Enterprise customers (nothing for you to do here). Common data: That can be used to store general sensitive data, common to all users. Common data is always stored encrypted in Make, such as Client ID and Secret for apps using OAuth Authorization Code, if you want to allow users to connect easily. Note that the Common data is only accessible by the Connections Communication tab.

Build it

Now that you know how the Connections component works, you can set it up for the Geocodify app. To access the Connections, click your Geocodify app from the Custom Apps menu. In the Connections component, click Create a new Connection.

Fill in the details:

Label: Geocodify API Key. (The best practice is to use: App Name + Auth Type).

Type: API Key (Choose this type because the API documentation indicates that you need an API key for the authentication).

Click Save.

Select the Parameters tab, and then remove the default parameter that is present.

Select, copy, and paste the following code.

[ { “name”: “apiKey”, “label”: “API Key”, “type”: “password”, “help”: “Enter the API Key provided by Geocodify. For details, see “required”: true, “editable”: true } ]

Save the changes, by clicking the button at the top right.

In the Communication tab, remove the code present. Select, copy, and paste the following code.

{ // Request “url”: “https://api.geocodify.com/v2/geocode”, // Absolute URL to t “qs”: { // Query parameters “api_key”: “{{parameters.apiKey}}” // Authorizes user by ap }, “response”: {

“error”: { // Error handling “message”: ”[{body.meta.code}}] {body.meta.error_de

} }, “log”: { “sanitize”: [ // Excludes sensitive parameters from logs. “request.qs.api_key” ] // Omit query string apy_key } }

Save the changes.

Let’s look at them in detail, starting from the Parameters tab. You specify one parameter for the API key. This is the only parameter that the user will have to input in the scenario.

name: [Required] Internal name of the parameter. Use it when you want to retrieve

the parameter.

label: Parameter name displayed in the module setup.

type: [Required] Data type of the parameter. help: Instructions for the user displayed in the module setup. It supports Markdown for text formatting.

required: Specifies if the parameter is required.

editable: (Only for the connection) It specifies whether the user can edit and modify the connection from the Connections page in Make.

Best practices

Help under parameters

Using a help directive, you may specify a hint of what is expected for the parameter when it is not that obvious from the label or the expected value is more complicated. The text should start with a capital letter and end with a period. Editable connection

We recommend allowing users to edit their connections after they create them. Updating a connection simplifies scenario and user credential maintenance when there’s a change in the user’s organization.

You can find the best practices here.

Let’s have a look at the updated Communication tab.

 

1/3 Request

Request that the apps engine will make to validate the credentials.

url: Absolute URL of the endpoint that is used for validation.

qs: Query string.

api_key: Key of the qs parameter as specified by the API docs. This means that it will use the apiKey that the user provides. 

2/3 Response

Instructions on how to display any error: [error code] error message.

This information is typically present in the API docs. Since it isn’t available in this case, you need to retrieve it manually.

Send a request with incorrect credentials in Postman, then check the response body to identify where the error code and message appear.

If available, it’s good practice to include the status code in the error response. 

3/3 Log

Indicates to omit the api_key parameter present in the query string of the request from the log.

Best practices

Connections

Every connection should have a way how to check if the used API Key/Token is valid (Validation Endpoint): the info block in your Connection component. That means each connection should have a part that uses the used API Key/Token against an endpoint that requires only the API Key/Token to run.

Error handling The error handling part should contain the HTTP status code and the error type.

The error handling code should correspond to the structure of the server response. The error object in our example contains the code and message fields. It is also important to show the status code of the error, this can be accessed using the statusCode keyword.

Sanitization

You should always sanitize the log, so no personal tokens and/or keys can leak.

You can find the best practices here.

Learn it

The Base component contains the common settings of the app that are inherited by all modules. The Base component doesn’t directly correspond to a visible part of the app, it simply holds general settings.

The common settings include:

Base URL: The API base URL used as the main address for all requests to the API.

Authorization: Authentication information and credentials.

Error Handling and Sanitization: Same as the Connections component.

If a module doesn’t define a setting, it follows what’s in the Base. However, if a module specifies a different value for the same setting, for example a different error handling directive, this overrides what’s present in the Base.

The Base component doesn’t contain any tabs, but just the code where you specify the

common directives and the common data if needed. Let’s have a look at the default code. The structure of the JSONC code of the Base component is very similar to the Communication

tab that you have set up in the Connections component.

Note that in this case you want to use the authentication parameters from the Connections

component, which is why you set that up first. To do this, use the component name followed by the

parameter’s name: connection.apiKey.

Build it

To build the Base component, remove the code that is present.

Then select, copy, and paste the following code.

{ // Default request configuration “baseUrl”: “https://api.geocodify.com/v2”, // Default base URL for “qs”: { // Default query parameters for all modules. “api_key”: “{{connection.apiKey}}” // API key, which user w },

// Default response handling “response”: { “error”: { // Error handling “message”: ”[{{body.meta.code}}] {{body.meta.error_ } },

“log”: { “sanitize”: [ // Excludes sensitive parameters from logs. “request.qs.api_key” // remove api_key query param ] } }

Save the changes.

Let’s look at it in detail.

 

1/4 baseURL

Contains the base URL of the API. Note that it contains the API version.

You will specify the different endpoints in the modules. 

2/4 qs

Contains the query parameter for authentication.

Notice that the apiKey parameter is taken from the Connections component and accessed using connection.apiKey 

3/4 response

Instructions on how to handle errors.

Notice that in this case the code is the same as in the Connections component. 

4/4 log

Instructions on the information that is saved in the logs.

sanitize specifies what needs to be omitted.

Notice that in this case the code is the same as in the Connections component.

Best practices

Base

The Base section should contain data that is common to all (or most) requests. At the very least, this should include the root URL, the authorization headers, the error-handling section, and the sanitization.

Base URL Make sure that the Base URL uses the URL of the API, which is shared among all modules or their majority.

Authorization and sanitization

The Base section should also have authorization, which is common for all modules. This authorization should use the API Key, Access Token, or Username and Password entered in the connection. The sanitization should hide all these sensitive parameters.

Error handling

Each service sends an error message when an error occurs. Most of the time this happens when the request has wrong parameters or values or when the service has an outage. That’s why error handling is required. The error handling code should correspond to the structure of the server response.

You can find the best practices here.

Modules

In Make, you can set up 6 different types of modules, each with a specific function.

Action: Triggers a single response from the API, such as adding a new location, deleting a location, or retrieving information about a place.

Search: Returns multiple results from the API, like searching for places or locations based on specific criteria. If the API returns an array of items, you can use the iterate directive to loop through the array and generate a bundle for each item.

Trigger (polling): Monitors changes in the application or service, such as triggering an action when a new location is added or updated.

Instant trigger (webhook): Listens to incoming requests from the third-party application when an event happens, such as reacting to a location update or a new event related to a place.

Universal: Allows making any arbitrary API calls to the service, such as querying location data or executing a custom geocoding request. It is the Make an API call module that you can see in most Make apps.

Responder: Sends processed data back to a webhook, such as the location information. In this course you will set up a Search module to retrieve the coordinates of an address.

Learn it

The Search module sends a request and returns multiple results. Use this module when you want to let users search for records.

Inside the Search module component there are 5 tabs:

Communication: Information on what the engine needs to do to manage the API

call (call the endpoint, process the response, pagination, etc). Remember that the following elements are inherited from the Base: base URL, error handling, log sanitize. If something needs to be changed, you can write it here, and it will override the settings of the Base component.

Static parameters: Input parameters that the user cannot map from other modules. They are only used for polling triggers, which don’t have Mappable Parameters.

Mappable parameters: Input parameters in the interface that the user can either enter manually or map from the output of other modules.

Interface: Labels of the module’s output added to make the output more straightforward and easy to interpret. By specifying it, there’s no need to first run the module in your scenario to get the output structure for mapping the elements.

Samples: Examples of data to help the users set up the module.

You’re going to set up the Search module from scratch, so you won’t be exploring any default code for this component.

Build it

The Search module sends one or more requests and returns multiple results. Use this module when you want to let users search for items or simply return multiple items.

From the Custom Apps menu> Geocodify, go to the Modules component and select + Create a new module. In the pop-up window you will need to fill in the module details. Let’s start by having a look at the different items before filling them in. 

 

1/7 Template

Select how you want the module to be pre-filled with code. The options are:

Blank module

Pre-fill with example code [selected by default]

Copy code from existing module 

2/7 Type

Choose one of the six module types described above. 

3/7 Connection

[Optional]

Link a connection to authenticate the API calls. 

4/7 Module action

[Optional]

Only for Action modules. 

5/7 Name

Module internal name. See instruction below the box for character restrictions. 

6/7 Label

Name of the module as shown in the scenario.

See Best Practices below for naming recommendations. 

7/7 Description

Description of the module.

Fill in the module setup as below: Template: Blank module (you will set it up from scratch)

Type: Search (to retrieve geolocalization details)

Connection: Geocodify (the connection you have created earlier)

Name: geocode

Label: Search Geolocation

Description: Provides longitude, latitude, and place details of a location (address, name of a place, or location).

Click Save.

Best practices

Type

Modules should be associated with the correct type, depending on their functionality.

Name

A name of a module […] should not match with any reserved word in JavaScript.

Label Every module should have a label that precisely describes the module’s use. For each type of module, there is a standard naming convention. But it may change depending on the functionality of the module. The label should be composed of the verb expressing the intended action (Create, Update, Watch, etc.) and the name of the entity being processed (Customer, Invoice, Table, etc).

Names of modules follow the English format and the sentence case capitalization. Basically, only the first letter of the first word in a sentence and proper nouns are capitalized, with all other letters and words in lowercase. Note that you might see some old apps still using Title Case (every word is capitalized except for articles, prepositions, and conjunctions), but new apps are using sentence case for module names.

These modules retrieve data from the service and allow retrieving one or more results. Compose the label using simple verbs like Search or List. Use the naming convention of the service you are implementing.

Description

In a few words, describe the functionality of the module. Write the description in the third person and capitalize only the first letter of the first word in the description (like a normal sentence structure).

You can find the best practices here. To set up the tabs, start with the Mappable parameters.

As mentioned earlier, this is the information the user needs to provide, which will appear in the

scenario as shown on the image.

In this case, the user must enter a location to geolocate, so you need to add a mappable parameter

for the location.

Select, copy, and paste the following code in the Mappable parameters tab.

// Defines “location” as module input parameters. [ { “name”: “location_info”, // Makes value accesible via “{{parameters “label”: “Location”, // Sets the user friendly label visible in the “type”: “text”, // Sets the type to text. “help”: “Type the location you want to geolocate”, // Sets the help “required”: true // Indicates this parameter is mandatory. } ]

Save the changes.

Then select, copy, and paste the following code in the Communication tab.

{ // Request to API endpoint. “url”: “/geocode”, // Endpoint relative to base URL “method”: “GET”, “qs”: { “q”: “{{parameters.location_info}}” // Required query param },

// Response handling “response”: { “output”: “{{body}}” // Return the body of the response } }

Save the changes.

Let’s have a look at them in detail.

Work through the images below to learn more. Mappable parameters

As you’ve seen before, you specify one parameter that the user has to input.

name: [Required] Internal name of the parameter. Use it when you want to access the parameter using {{parameters.name}}.

label: Parameter name displayed in the module setup.

type: [Required] Type of the parameter.

help: Instructions for the user displayed in the module setup. It supports Markdown for text formatting.

required: Specifies if the parameter is required.

Communication This section contains all the details specific to this module. The base URL, authentication, error handling, and sanitization are inherited from the Base and do not need to be specified.

url: The API endpoint. Since it starts with /, it is joined to the base URL. Note that if the URL starts with https://, it will override the base URL.

method: The default method is GET, so it could have been omitted in this case.

qs: Query parameter containing the location to geolocate. Note that you access it by using parameters.location_info.

response: Defines the output returned, which in this case is the whole body of the response.

Leave all the other tabs as they are, including the Interface. This means that you won’t apply any filtering or customization to the output, but all the information from the API will be returned as is. This is a topic for a more advanced course, stay tuned!

Test it!

You’re all set and it’s time to test your app in a scenario.

Work through the images below to learn more.

In Make create a new scenario and add the Geocodify> Search Geolocation module that you have just created. Notice that it has the Private tag.

Create Create a connection to insert your authentication details. Paste the API key from the Geocodify API in the API Key field and you can rename the connection if you want.

Click Save to save the connection.

The app engine will make the call to the API specified in the Connections element to validate the credentials. If everything is working fine, no error message is displayed.

Insert the address you want to geolocate, for example Champ de Mars, 5 Avenue Anatole France, 75007 Paris, France. This is the Location parameter you set up in the Mappable parameters tab. Click Save to save the module.

Save the scenario. A pop-up appears appears asking for confirmation to install the app in your organization.

Click Yes on the pop-up to install the app in your organization.

Click Run once to run the scenario. Open the Output to retrieve the coordinates. They are under Output> Bundle 1> response> features> 1> geometry> coordinates.

This happens because you chose to return the response as is, without filtering or customization. In future courses, you’ll learn how to use the interface to tailor the output and return only the necessary information in a structured format.

Make the module visible

There’s one final step to allow members of the organization to use this new module: you need to make it visible to everyone. When you create the module, it’s hidden by default. Even if the app is installed, the module won’t appear in the scenario editor for other users unless you make it visible.

To do so, go to the specific module in the app setup and turn it ON. It will now have the visible

tag.

And that’s it! This marks the end of your first introduction to the world of custom apps! You now understand why a custom app is necessary, its structure and components, and how to use API docs to set up a simple custom app. But there’s so much more you can do to build an app that works the way you want. That’s a story for another time and other courses.

Congratulations on completing the Getting started with custom apps course.

We’d love to hear from you! Rate the course and share your thoughts and impressions with us.

RATE THIS COURSE

When you are done, click Go to dashboard to return to the Academy.