Skip to main content

Embedding Marketplace

You can embed the Integration Marketplace into your application with just a few lines of code, giving your customers a native integration deployment experience. This article details how to embed Prismatic's integration marketplace into your application, including how to authenticate users in Prismatic seamlessly using your existing authentication system.

Installing Prismatic's Marketplace Code#

To embed marketplace, you must include some Prismatic JavaScript code in your client application. You have two choices for how to incorporate that code: you can add the @prismatic-io/marketplace NPM package to your web app project, or you can add a <script> tag to your app.

Installing Marketplace Through NPM#

Marketplace NPM version

If your application is written in Node.js, you can include Prismatic's JavaScript code as a Node import. Install the Prismatic Marketplace Node.js package from NPM with npm or yarn:

npm install @prismatic-io/marketplace
# or
yarn add @prismatic-io/marketplace

Then, for any page that needs to invoke a prismatic.* function, include the @prismatic-io/marketplace package at the top of the file:

import prismatic from "@prismatic-io/marketplace";

Installing Marketplace with a Script Tag#

We recommend installing marketplace through NPM

Installing Marketplace through the script tag is great for prototyping and testing, but for production use we recommend installing Marketplace through NPM. The TypeScript NPM package gives you advanced features, like code completion and type safety, and lets you stay pinned to a version of Marketplace that you know works for you.

You can include the Prismatic Marketplace JavaScript code with a <script> HTML tag. To include the script from Prismatic's default app URL, add this snippet:

<script src="https://app.prismatic.io/cdn/marketplace/latest/index.js"></script>

Prismatic may change marketplace functionality at any time, so there is some risk involved with including a latest script tag. If you choose to install marketplace with a script tag, we recommend that you pin your app to a specific version of marketplace. Take note of the current latest version (Marketplace NPM version), and replace latest with that version:

<script src="https://app.prismatic.io/cdn/marketplace/3.0.0/index.js"></script>

If you white-label Prismatic (i.e. run Prismatic under a domain you own, like https://integrations.my-example-company.com), use that domain instead:

<script src="https://integrations.my-example-company.com/cdn/marketplace/3.0.0/index.js"></script>

Once the script has loaded, prismatic.* functions (described below) are available for you to use.

Initialize the Prismatic Client#

When Prismatic is embedded in your app, it's presented in an iframe that by default points to Prismatic's application URL (https://app.prismatic.io).

To initialize the Prismatic client, run the init function:

prismatic.init();

If you use a custom white-label domain (something like https://integrations.my-example-company.com), you can point the iframes that you embed your white-label domain instead. To do that, add this snippet of code:

Optional white-label iframe config
prismatic.init({  prismaticUrl: "https://integrations.my-example-company.com",});

Authenticating Users#

One big advantage of embedding the integration marketplace is that users don't need to be assigned an additional set of credentials to remember. They can log in to your application, and you can provide them with an authentication token that allows them to deploy Prismatic integrations. You do this by generating a JSON Web Token (JWT) that is signed by a unique private key that you get from Prismatic. The JWT contains information about the user from your system. When Prismatic is presented a signed JWT, the JWT signature is verified and the user is granted a customer role of Marketplace, which allows them to deploy integrations for their specific customer in Prismatic.

JWT Signing Keys#

Before you can generate a JWT, you will need a valid signing key from Prismatic. Within Prismatic click on your organization name on the bottom of the left-hand sidebar, and then open the Embedded tab. Click the + Add signing Key button. Note: You must be an owner or admin to create a signing key.

You will be presented with a private signing key. Store this key somewhere safe - it's the key you'll use to validate that users are authenticated within your application.

Get signing key in Prismatic app
Private keys are not stored in Prismatic

Prismatic does not store the private signing key that is generated, and only saves the last 8 characters so you can easily match up a private key you have with one in our system. Instead, we store the corresponding public key to verify signatures of JWTs you send. Save the private key that you generate somewhere safe. If it's ever compromised, or you lose it, you can deactivate old keys and generate a new one.

Create and Sign a JWT#

Now that you have a signing key, you can create and sign a JSON web token (JWT). Your backend API (not your frontend) should generate a JWT for your users, and your frontend client should request a signed JWT from your backend API.

Do your JWT generation on the backend

Generate the JWT tokens on the backend. Baking JWT generation (including the signing key) into your frontend presents a security problem - someone with the signing key could sign their own JWT and pretend to be anyone.

Most programming languages that APIs are written in have a JWT library for generating tokens - see jwt.io.

The JWT that you generate for a user should have the following properties:

  • The header should indicate that it's HMAC with SHA-256 encrypted, and should read:
    {  "alg": "RS256",  "typ": "JWT"}
  • The private signing key you downloaded.
  • A payload with a few fields:
    • A unique user ID sub
    • The user's name (optional)
    • Your organization ID, found on the Embedded tab where you generate signing certificates
    • The external ID of the customer the user belongs to
    • A signing time (current time) iat
    • An expiration time exp
      Example JWT Payload
      {  "sub": "2E52B7CB-071B-4EA2-8E9D-F64910EBDBB1",  "name": "Phil Embedmonson",  "organization": "T3JnYW5pemF0aW9uOmU5ZGVhZDU5LWU3YzktNDNkMi1hNjhhLWFhMjcyMzEyMTAxNw==",  "customer": "abc-123",  "iat": 1631676917,  "exp": 1631680517}
Use unique identifiers as JWT subjects

The sub (subject) within the JWT identifies the user who is logged in to your system. The sub value can be any unique identifier - a UUID, email address, etc.

A customer user with that identifier will be created in Prismatic if it doesn't already exist, and will be granted permissions to configure and deploy instances to the customer they're assigned to (you assign the user to a customer in the examples below).

Here are a couple of code snippets for JavaScript and Python that would create a valid JWT to authenticate a user in Prismatic:

import jsonwebtoken from "jsonwebtoken";
/* This is for illustrative purposes only; Obviously don't hard-code a signing key in your code.*/const signingKey = `-----BEGIN PRIVATE KEY-----MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDP3+OrT0IXqCu4EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEc5R7QVzxgmGRXjPZGPf5huA1-----END PRIVATE KEY-----`;
const currentTime = Math.floor(Date.now() / 1000);
const token = jsonwebtoken.sign(  {    sub: "2E52B7CB-071B-4EA2-8E9D-F64910EBDBB1", // Some unique identifier for the user    name: "Phil Embedmonson", // Optional    organization:      "T3JnYW5pemF0aW9uOmU5ZGVhZDU5LWU3YzktNDNkMi1hNjhhLWFhMjcyMzEyMTAxNw==",    customer: "abc-123", // This is an external ID of a customer    iat: currentTime,    exp: currentTime + 60 * 60, // 1 hour from now  },  signingKey, // Store this somewhere safe  { algorithm: "RS256" });

Use the JWT to Authenticate the User#

Now that a user in your application has a signed JWT from the backend, you can authenticate them with the Prismatic library using the prismatic.authenticate() function in your frontend application:

// Some function that fetches the JWT from your API:const token = getJwtToken();
try {  await prismatic.authenticate({ token });} catch (error) {  console.error(`Authentication failed with error ${error}`);}

If your customer or organization ID in your JWT are incorrect, if your JWT is not signed correctly, or if the JWT is expired, prismatic.authenticate() will throw an error.

Embed the Integration Marketplace#

Once a user has been authenticated, you can display the integration marketplace to them using the prismatic.showMarketplace() function. The showMarketplace() function takes three optional arguments:

  • usePopover is a boolean that determines if the marketplace should display as a popover.
  • selector identifies which element in the DOM to inject the iframe into when usePopover is false.
  • theme can override custom theming default behavior, and can be set to "LIGHT" or "DARK".

iframe Injection Method#

When showPopover is set to false, an iframe HTML element is injected into an element that you select with the selector argument. The iframe contains the integration marketplace.

For example, if you have a section of your app that reads:

<div id="integration-marketplace-placeholder" style="height:100%">  Loading...</div>

You can inject the integration marketplace iframe into that div, replacing the "Loading..." text, by invoking:

prismatic.showMarketplace({  selector: `#integration-marketplace-placeholder`,  usePopover: false,});

The result is that the integration marketplace appears to be a portion of the rest of your application:

Prismatic integration marketplace embedded in your app

Note: at this point marketplace has not been themed to match your app. To match your app branding, see Theming Embedded Marketplace below.

Popover Method#

If you elect to set usePopover to true, a popover will be opened containing the integration marketplace:

prismatic.showMarketplace({  usePopover: true,});
Enable popover for Prismatic embedded marketplace

Filtering Integrations#

You can choose to show a subset of your integrations by applying filters to your showMarketplace() invocation. You can filter your integrations by category or label.

For example, if you would like to show only integrations with the category "ERP" and the label "enterprise" in an embedded marketplace, you can issue this invocation:

Filter by category and label
prismatic.showMarketplace({  selector: `#my-div-id`,  usePopover: false,  filters: {    category: "ERP",    label: "enterprise",  },});

You can choose to filter by category, label, or both. If you filter by both, integrations will appear if they match both category and label.

Configure a Specific Integration#

If you'd like to use your own UI elements (a button, div, hyperlink, etc) for selecting an integration to deploy, you can.

Invoke the prismatic.configureIntegration() function from your UI element to display a configuration screen for a specific integration by passing in the name of the integration as integrationName. You can pass in other display information (like usePopover and selector) as you would with the iframe injection and popover methods described above.

You can also pass in an optional skipRedirectOnRemove boolean, which defaults to false. This determines if your user should be redirected to the list of integrations upon removing an integration. If you are embedding marketplace, you probably want to keep this value false. If you're wrapping our API and handling displaying of integrations yourself, you might want this to be true.

For example, if you would like your "Salesforce" integration to appear when someone clicks one of your buttons, you could invoke configureIntegration like this:

const deploySalesforce = () => {  prismatic.configureIntegration({    integrationName: "Salesforce",    skipRedirectOnRemove: false,    usePopover: true,  });};
<Button onClick={deploySalesforce}>Configure Salesforce Integration</Button>;

Listening to Marketplace Events#

The embedded marketplace emits custom JavaScript events when certain things happen:

  • An INSTANCE_CREATED event is emitted the first time an integration's configuration screen is opened.
  • An INSTANCE_CONFIGURATION_OPENED event is emitted when an instance configuration screen is opened.
  • An INSTANCE_CONFIGURATION_LOADED event is emitted when an instance configuration screen has loaded. This is a good event to hook into if you want to programmatically set config variables.
  • An INSTANCE_CONFIGURATION_CLOSED event is emitted when an instance configuration screen is closed.
  • An INSTANCE_DELETED event is emitted when an integration has been deactivated (the instance has been deleted).

You can subscribe to these events so your app can take additional steps when an instance has been created, configured, deleted, etc. All events return data structured similar to this (except for INSTANCE_CONFIGURATION_LOADED, which returns additional data):

{  "event": "INSTANCE_CONFIGURATION_OPENED",  "data": {    "customerId": "Q3VzdG9tZXI6OThiMjU3MDUtZmMzNC00NWYwLTk0ZDItODA0ZjFkYzEyYTZk",    "customerName": "Smith Rockets",    "instanceId": "SW5zdGFuY2U6YzJlYTliZjEtY2Y3MS00NTg1LTk2MjMtYjZhNDAxYjQyNWRm",    "instanceName": "Salesforce",    "integrationName": "Salesforce",    "integrationVersionNumber": 18  }}

In this example we log out the name of the customer and what integration they opened:

import { PrismaticMessageEvent } from "@prismatic-io/marketplace";
window.addEventListener("message", (event) => {  // Check if the message event is of type INSTANCE_CONFIGURATION_OPENED  if (    event.data.event === PrismaticMessageEvent.INSTANCE_CONFIGURATION_OPENED  ) {    // Grab some data    const { customerName, integrationName } = event.data.data;    // Log out the customer and integration name. You can replace this with whatever data or helper functions you want    console.log(      `${customerName} opened the configuration page for ${integrationName}`    );  }});

Similar event listeners can be added for when an instance configuration page is closed or loads, or an instance is initially created or deleted.

Dynamically Setting Config Variables in Marketplace#

You can programmatically set values for your customers' config variables by leveraging marketplace events. This is handy if you know some value (an API key, endpoint, etc), and would like to set a config variable on your customer's behalf (so they don't need to look up the values themselves).

When your app receives an INSTANCE_CONFIGURATION_LOADED event message, the message's payload contains the properties listed above, plus current config variable values.

You can inspect that event's data, and conditionally set values for some config variables using the prismatic.setConfigVars() function. Let's look at the event message, and how to respond to it with some config variable values:

Here's what the INSTANCE_CONFIGURATION_LOADED payload looks like. The event message's .data.configVars property contains all currently set config variables and their values:

Example INSTANCE_CONFIGURATION_LOADED event payload
{  "event": "INSTANCE_CONFIGURATION_LOADED",  "data": {    "instanceId": "SW5zdGFuY2U6ZTE4NTNkYWItZjJhMi00OGIyLTk1ZWItODRjYzQ3YzRiMzc4",    "instanceName": "Test Embedded config vars",    "integrationName": "Test Embedded config vars",    "integrationVersionNumber": 1,    "customerId": "Q3VzdG9tZXI6OThiMjU3MDUtZmMzNC00NWYwLTk0ZDItODA0ZjFkYzEyYTZk",    "customerName": "Smith Rockets",    "configVars": {      "Acme Connection": {        "inputs": {          "username": { "value": "" },          "password": { "value": "" }        }      },      "My Key/Value List": {        "value": [],        "collectionType": "keyvaluelist",        "codeLanguage": null,        "dataType": "string",        "pickList": null,        "scheduleType": null,        "timeZone": null      },      "My String": {        "value": "",        "collectionType": null,        "codeLanguage": null,        "dataType": "string",        "pickList": null,        "scheduleType": null,        "timeZone": null      },      "My List": {        "value": [],        "collectionType": "valuelist",        "codeLanguage": null,        "dataType": "string",        "pickList": null,        "scheduleType": null,        "timeZone": null      },      "My String With Default": {        "value": "Some Default",        "collectionType": null,        "codeLanguage": null,        "dataType": "string",        "pickList": null,        "scheduleType": null,        "timeZone": null      },      "My List With Default": {        "value": ["Foo1", "Foo2"],        "collectionType": "valuelist",        "codeLanguage": null,        "dataType": "string",        "pickList": null,        "scheduleType": null,        "timeZone": null      },      "My Picklist": {        "value": "",        "collectionType": null,        "codeLanguage": null,        "dataType": "picklist",        "pickList": ["Foo", "Bar", "Baz"],        "scheduleType": null,        "timeZone": null      },      "My Boolean": {        "value": false,        "collectionType": null,        "codeLanguage": null,        "dataType": "boolean",        "pickList": null,        "scheduleType": null,        "timeZone": null      }    }  }}

The getMessageIframe Helper Function#

Your app needs to know which iframe to send a setConfigVars message to. Your app might have multiple iframes, and potentially multiple instances of the embedded marketplace on a single page.

The getMessageIframe function helps to identify which iframe generated the INSTANCE_CONFIGURATION_LOADED event.

If you would like to send a setConfigVars message to a specific iframe, you can instead pass a selector property to the setConfigVars function (like you did for prismatic.showMarketplace()):

setConfigVars message by selector
setConfigVars({  selector: "#my-marketplace-container",  configVars: {    "My Config Var Name": { value: "My config var value" },  },});

Theming Embedded Marketplace#

You can theme your embedded marketplace to match your app's look and feel. To create a custom theme for your customers, click your organization's name on the bottom of the left-hand sidebar, and then open the Theme tab. Note: You need to have the admin or owner role to edit custom themes.

The left side of the Theme tab shows properties (colors and styles) that you can customize, and the right side shows a preview of how various UI elements would look given those custom properties.

Theming the Prismatic integration marketplace for your app

Your embedded themes will be reflected in your embedded application:

Example of themed integration marketplace

Light and Dark Mode Themes#

Under Theme Mode you have four options:

  • Light and Dark determine what the Prismatic app itself looks like when you use "dark" or "light" mode. Each of your team members can configure dark or light mode settings from their profile settings page, or they can choose to have Prismatic follow their operating system's dark/light mode theme.

    Note: Your customers will not see Light or Dark themes unless you create customer users for them and they log directly in to Prismatic.

  • Embedded Light and Embedded Dark determine the theme for your embedded marketplace. These are the themes that your customers using embedded marketplace in your app will see.

By default, embedded marketplace follows your customers' operating system dark/light mode theme settings. That's helpful if your app has dark and light modes that also follow OS theme settings - the embedded marketplace will swap between dark and light alongside your app.

If you would like to override the dark/light mode behavior for embedded, and only show either the dark or light theme, add a theme property to your showMarketplace invocations:

Only show light-mode theme
prismatic.showMarketplace({  selector: `#my-embedded-div`,  usePopover: false,  theme: "LIGHT", // or "DARK"});

Hiding UI Elements in Marketplace#

You can optionally hide the Back to Marketplace link, some tabs from the instance screen, and elements of the instance configuration wizard. This is useful if you want to prevent your customers from running tests from the Test tab or reconfiguring alert monitors for themselves.

To disable certain UI elements, add a screenConfiguration block to your prismatic.showMarketplace() or prismatic.configureIntegration() invocations:

Hide the 'back' link and 'monitors' and 'test' tabs
prismatic.showMarketplace({  selector: `#${id}`,  usePopover: false,  theme: "LIGHT",  screenConfiguration: {    instance: {      hideBackToMarketplace: true,      hideTabs: ["Monitors", "Test"],    },    configurationWizard: {      hideSidebar: true,      isInModal: true,    },  },});
  • instance.hideBackToMarketplace determines whether or not to hide the Back to Marketplace link in the instance configuration screen and defaults to false.
  • instance.hideTabs determines which tabs to hide from the instance configuration screen. You can choose from the Test, Executions, Monitors or Logs tabs. No tabs are hidden by default.
  • configurationWizard.hideSidebar hides the left-hand sidebar from the configuration wizard (the config wizard page titles and numbers).
  • configurationWizard.isInModal affects if the config wizard should appear over the current page in a modal. When set to true, it's assumed that your embedded marketplace is already in a modal, (and since a modal-in-a-modal isn't the best look), opens the config wizard to fill its containing <div>.

If you would like to apply your preferences globally (in the case that you have multiple invocations showMarketplace() and configureIntegration()), you can configure settings when you run prismatic.init():

Hide UI elements globally
prismatic.init({  screenConfiguration: {    instance: {      hideBackToMarketplace: true,      hideTabs: ["Test", "Monitors"],    },  },});

Screen configuration settings in prismatic.init() can be overridden within a specific showMarketplace() or configureIntegration() invocation. hideTabs properties are not merged if yo do this - the screenConfiguration settings in showMarketplace / configureIntegration completely override the default settings in init.