Content Security Policy (CSP)

Last updated:

Content Security Policy (CSP) is a layer of security created by the owners of a web application. 

An effective (strict) CSP restricts which resources are allowed to a small set of domains. This has the potential to impact Pendo by preventing Pendo from loading or operating correctly. For example, the agent might not be called or guides might not load. For this reason, you might need to make an adjustment to your CSP to allow Pendo full functionality. 

This article outlines the minimum required directives in your CSP to allow Pendo to have full functionality. If you're using Feedback, see Feedback's Content Security Policy.

CSP overview

CSP is a method of specifying domains from which specific types of content in your web application can be loaded. A CSP can specify sources that are allowed for specific types of content, such as JavaScript, CSS, and images.

CSP is often used to prevent Cross Site Scripting (XSS) and data injection attacks, especially if you manage sensitive data. You might also use CSP if you want to:

  • Ensure that page resources, such as images and frames, are only loaded from trusted sources.
  • Prevent your application from being framed by untrusted domains.
  • Transparently upgrade all resource requests to HTTPS.

You enable CSP by setting the Content-Security-Policy HTTP response header or as a meta tag on the main document. For example, an application can define a policy by setting the following header:

Content-Security-Policy: default-src https:; script-src 'nonce-{random}'; object-src 'none'

Real policies are typically more complicated. The above example policy requires all resources to load over HTTPS, allows only script elements with the correct nonce attribute, and prevents plugins from loading.

Errors caused by CSP

If you notice any of the following issues after installing Pendo, you might need to check your CSP. 

  • No analytics or guide events appearing for your application.
  • Guides not loading at all in your application.
  • Visual Design Studio not launching.
  • No replays appearing for your application.
  • Error messages in your console that look like the following:

Screenshot 2023-11-17 at 11.26.37 AM.png

Find your current CSP

To find your current CSP:

  1. Open the Network tab in your browser console.
  2. Open the request of the main page.
  3. Find the CSP listed under Content-Security-Policy in the Headers tab.

    CSP.png
  4. If there’s no CSP response header, inspect the HTML of the page and look for a Content-Security-Policy <meta> tag in the <head> of the document.

    CSP.png

Standard required directives

Required directives are different depending on your agent delivery settings. To know which directives are required for Pendo to work fully in your application, you must first take note of your guide delivery settings. To find these:

  1. Go to Settings > Subscription settings.
  2. Open the Applications tab.
  3. Find and open the relevant app from your Applications list.
  4. Open the Agent Settings tab.
  5. Select Manage Production Settings.
  6. Note which option is selected: Standards, XHR, or JSONP.

The following directive changes are required for Pendo to have full functionality with a strict CSP. These are organized by the following content types, all of which are needed to edit and load guides:

  • JavaScript (directive: script-src)
  • CSS (directive: style-src)
  • Images (directive: img-src)
  • Data (directive: connect-src)
  • Frames (directives: frame-src and frame-ancestors)
  • Workers (directive: worker-src)

Replace SUB_ID with your Subscription ID. Your Subscription ID is displayed in the page URL when you're signed in to Pendo. It uses the following format: https://app.pendo.io/s/[SUB_ID]/. The subscription ID immediately follows /s/. Don't accidentally copy the unique ID for a guide or report that populates at the end of the URL path when navigating Pendo.

You may include https:// before any hostnames if desired.

JavaScript directive changes

Directive: script-src

The following sources (hosts) allow Pendo scripts to be downloaded and run.

Source Description
cdn.pendo.io

Location of the Pendo agent, referenced in your install script ("snippet"). This is where the Pendo agent is downloaded from by default. Needed to download Pendo.

pendo-io-static.storage.googleapis.com

Location of the Pendo agent downloaded for staging domains. Needed to download the agent on staging domains as well as the agent debugger.

pendo-static-{{ SUB_ID }}.storage.googleapis.com

Location of all guide content. Needed to download guide code blocks.

data.pendo.io

Used to download the list of guides that a visitor is eligible for. This is only needed for JSONP delivery methods.

app.pendo.io

Only required to use the Visual Design Studio.

'unsafe-inline'

Only required if using custom code blocks, Resource Center integrations, or classic guides while using the Visual Design Studio. If you don't want to use 'unsafe-inline', see Unsafe directive alternatives in this article.

'unsafe-eval'

Only required if using custom code blocks, Resource Center integrations, or classic guides while using the Visual Design Studio. If you don't want to use 'unsafe-eval', see Unsafe directive alternatives in this article.

CSS directive changes

Directive: style-src

The following sources (hosts) allow Pendo styles to be used on your site.

Source Description
pendo-io-static.storage.googleapis.com

Default Guide CSS is loaded from this URL. Only needed if classic guides are enabled to download default guide CSS.

pendo-static-{{ SUB_ID }}.storage.googleapis.com

Guide styles and Global CSS. Needed to download global guide CSS and stylesheets for custom code blocks.

'unsafe-inline'

Used to support guide pseudo styles (hover, carets in the Resource Center, number scale) and styles when the Visual Design Studio is launched. If you don't want to use 'unsafe-inline', see Unsafe directive alternatives in this article.

app.pendo.io

Only required to use the Visual Design Studio.

Images directive changes

Directive: img-src

The following sources allow images hosted by Pendo to be displayed on your site.

Source Description
cdn.pendo.io

Only needed for badges in classic guides.

data.pendo.io 

Events are sent using the image src to this url. Needed to send events to Pendo.

pendo-static-{{ SUB_ID }}.storage.googleapis.com

Guide images are downloaded from this url. Needed to download any uploaded guide images.

app.pendo.io

Only required to use the designer.

data:

Default badge images. If using custom images for badges, then this isn't needed.

Data directive changes

Directive: connect-src

The following sources allow scripts on your pages to communicate with Pendo.

Source Description
data.pendo.io Required for event communication and Session Replay.
pendo-static-{{ SUB_ID }}.storage.googleapis.com

Load the guide structure files here. Needed to load and edit guide content.

app.pendo.io

Only required to use the Visual Design Studio.

Frame directive changes

Directive: frame-src

The following sources allow iframes to load Pendo content on your site.

Source Description
app.pendo.io

The Visual Design Studio is loaded from this URL. Only required to use the Visual Design Studio.

portal.pendo.io

Allows the ideas portal in Listen to be loaded through an iframe.

The following source allows Pendo to load your site pages within a <frame>, which is only needed if you're using the Classic Designer.

Source Description
app.pendo.io

The Pendo host from where the Classic Designer loads your application. Only required to design guides with the Classic Designer.

Workers directive changes

Directive: worker-src

The following source allows the Pendo agent to start a worker thread to minimize performance impact on your application.

Source Description
blob:

The Pendo agent starts a web worker to compress and send session-capturing data for Session Replay. Offloading work to a worker allows for improved performance of session capturing.

Guide video providers

You must ensure that the appropriate locations for your videos are permitted in your CSP. These locations depend on which video providers you want to use in your guides.

Directive: frame-src

Source Provider
https://players.brightcove.net Brightcove
https://www.loom.com Loom
https://web.microsoftstream.com

Microsoft Stream (Classic)

https://{ORG_ID}.sharepoint.com Microsoft Stream (on SharePoint)
https://player.vimeo.com

Vimeo

https://play.vidyard.com

Vidyard

https://fast.wistia.net

Wistia

https://www.youtube.com

YouTube

Directive: img-src

Source Provider
https://cdn.loom.com Loom thumbnails
Pendo bucket

Microsoft Stream (Classic) thumbnails

Pendo bucket Microsoft Stream (on SharePoint) thumbnails
https://i.vimeocdn.com

Vimeo thumbnails

https://cdn.vidyard.com and

https://cdn-cf.vidyard.com

Vidyard thumbnails

https://embed-ssl.wistia.com

Wistia thumbnails

https://img.youtube.com

YouTube thumbnails

Font directive changes 

Directive: font-src

The font source allows the Pendo agent to load its own font.

Source Description
cdn.pendo.io Used to load fonts for the Visual Design Studio, the Pendo agent debugger, and guide preview mode.

Location-based changes

This section lists location-based changes to the source for US1, EU, and Japan customers. This is only relevant if your subscription is hosted in a different data environment to the default US environment. You can check which data environment your subscription is hosted in by looking at the URL you use to access Pendo:

  • The URL for the default US data environment is app.pendo.io.
  • The URL for the US1 data environment is us1.app.pendo.io.
  • The URL for the EU data environment is app.eu.pendo.io.
  • The URL for the Japan data environment is app.jpn.pendo.io.

You only need to specify one data environment in your CSP. This means that you should only use the standard URLs outlined earlier in this article or the URLs from one of the other data environments in this section (US1, EU, or Japan). You shouldn't use URLs for more than one data environment.

US1

Original
US1
app.pendo.io us1.app.pendo.io
portal.pendo.io us1.portal.pendo.io
data.pendo.io

us1.data.pendo.io

cdn.pendo.io

us1.cdn.pendo.io

pendo-io-static.storage.googleapis.com

pendo-us1-static.storage.googleapis.com

pendo-static-{{ SUB_ID }}.storage.googleapis.com

pendo-us1-static-{{SUB_ID}}.storage.googleapis.com

EU

Original
EU
app.pendo.io app.eu.pendo.io
portal.pendo.io portal.eu.pendo.io
data.pendo.io

data.eu.pendo.io

cdn.pendo.io

cdn.eu.pendo.io

pendo-io-static.storage.googleapis.com

pendo-eu-static.storage.googleapis.com

pendo-static-{{ SUB_ID }}.storage.googleapis.com

pendo-eu-static-{{ SUB_ID }}.storage.googleapis.com

Japan

Original
Japan
app.pendo.io app.jpn.pendo.io
portal.pendo.io portal.jpn.pendo.io
data.pendo.io

data.jpn.pendo.io

cdn.pendo.io

cdn.jpn.pendo.io

pendo-io-static.storage.googleapis.com

pendo-jp-prod-static.storage.googleapis.com

pendo-static-{{ SUB_ID }}.storage.googleapis.com

pendo-jp-prod-static-{{SUB_ID}}.storage.googleapis.com

Required directives for custom CNAME

If you're using CSP with CNAME, add the sources below to the existing Pendo standard required directives while setting up CNAME with Pendo's Support team. After CNAME configuration is complete and tested, directives can be simplified to just the custom CNAME configuration, below.

JavaScript directive changes

Directive: script-src

The following sources (hosts) allow Pendo scripts to be downloaded and run.

Source Description
content.pendo.example.com

Location of the Pendo agent and guide content.

data.pendo.example.com

Used to download the list of available guides for the JSONP guide-delivery method.

app.pendo.io

Only required to use the the Visual Design Studio.

'unsafe-inline'

Only required if using custom code blocks or classic guides in the Visual Design Studio.

'unsafe-eval'

Only required if using custom code blocks or classic guides while in the Visual Design Studio.

CSS directive changes

Directive: style-src

The following sources (hosts) allow Pendo styles to be used on your site.

Source Description
content.pendo.example.com

Guide styles, global CSS, and default CSS are loaded from this domain.

'unsafe-inline'

Used to support guide pseudo styles (hover, carets in the Resource Center, number scale) and styles when the Visual Design Studio is launched.

app.pendo.io

Only required to use the Visual Design Studio.

Images directive changes

Directive: img-src

The following sources allow images hosted by Pendo to be displayed on your site.

Source Description
content.pendo.example.com

Guide images are downloaded from this URL.

data.pendo.example.com

Events are sent using the image src to this url. Needed to send events to Pendo.

app.pendo.io

Only required to use the designer.

data:

Default badge images. If using custom images for badges, then this isn't needed.

Data directive changes

Directive: connect-src

The following sources allow scripts on your pages to communicate with Pendo.

Source Description
data.pendo.example.com Required for event communication and Session Replay.
content.pendo.example.com

Load the guide structure files here. Needed to load and edit guide content.

app.pendo.io

Only required to use the Visual Design Studio.

Frame directive changes

Directive: frame-src

The following sources allow iframes to load Pendo content on your site.

Source Description
app.pendo.io

The Visual Design Studio is loaded from this URL. Only required to use the Visual Design Studio.

Directive: frame-ancestors

The following source allows Pendo to load your site pages within a <frame>, which is only needed if you're using the Classic Designer.

Source Description
app.pendo.io

The Pendo host from where the Classic Designer loads your application. Only required to design guides with the Classic Designer.

Workers directive changes

Directive: worker-src

The following source allows the Pendo agent to start a worker thread to minimize performance impact on your application.

Source Description
blob:

The Pendo agent starts a web worker to compress and send session-capturing data for Session Replay. Offloading work to a worker allows for improved performance of session capturing.

Compatible guide content

While Pendo is compatible with strict CSP directives, it is the user’s responsibility to ensure the guide content is compatible with your CSP restrictions.

If unsafe-inline is not present within the style-src and script-src directives, inline CSS and JavaScript within the HTML tab of the guide will not function correctly. To prevent an unexpected guide experience, all inline styles and scripts should be moved to the CSS and JS tabs of the guide code block or template.

With properly set minimal CSP directives (no inline directives), you should be able to fully use the Pendo Designer to show and tag your features. The X-Frame-Options plugin should enable you to use the Designer in guide editing mode with strict CSP. It is important to test guide content outside of the designer and with the X-Frame-Options plugin turned off.

Example of strict CSP compatible content

The basic concept is to remove all "unsafe-inline" styling and JavaScript.

For example, all of the inline styling and JavaScript within this HTML button:

<button class="_pendo-guide-next_" style="color:blue;" onclick="pendo.onGuideAdvanced()">Next</button>
would be distributed across the HTML, CSS, and JS tabs of the guide. The below example illustrates how to break down elements in guide content. You or your team’s developers may have a different or even better approach:

HTML

<button class="_pendo-guide-next_ blue-button">Next</button>

CSS

.bluebutton { color: blue; }

JavaScript

(function wireGuideAdvanceButton (step) { step && step.attachEvent(step.guideElement[0], 'click', function (e) { var advanceButton = pendo.dom(e.target || e.srcElement).closest('._pendo-guide-next_'); if (advanceButton.length) { pendo.onGuideAdvanced(); } }); })(step,guide);

Trusted types

Trusted types are an experimental technology currently only supported by Chromium-based browsers. If your application requires the extra XSS protection provided by trusted types, add the following directive to your CSP header: trusted-types pendo;. Trusted types support requires agent version 2.184.0 or higher.

X-Frames-Options header

We strongly recommend using the frame-ancestors directive from the official Content Security Policy (CSP) Level 2 specification instead of using the unofficial X-FRAME-OPTIONS header.

If switching to CSP is not an option, you can still use the Pendo in-app designer one of two ways:

  • Browser plugin. These are created by third parties, which means that Pendo doesn't own or maintain either of the extensions.
  • Updating the ALLOW-FROM value. We tested this on Firefox 43. This isn't an official standard and there are various implementations that might not support this value. You must specify the app.pendo.io URI. You can only include one URI per ALLOW-FROM, separated by a semi-colon. X-Frame-Options: ALLOW-FROM https://app.pendo.io

Unsafe directive alternatives

If you choose not to add unsafe-inline and unsafe-eval to your script-src, you can't preview your custom code blocks from within Visual Design Studio. Instead, you must either:

  • Save the guide, close the Visual Design Studio, and then preview the guide from the guide's details page.
  • Push the guide to Staging and then then view the guide in your staging environment.

This doesn't affect you if you don't use code blocks or Resource Center integrations in a guide.

Note: While editing guides with code blocks or Resource Center integrations, a CSP error might appear in the development console for script-src. You can ignore this error. 

If you choose not to add unsafe-inline to your style-src, you must replace unsafe-inline with a nonce that's passed to the agent initialization method with the key inlineStyleNonce, which can be found in our Guides API documentation. The agent and the Visual Design Studio adds this nonce to all inline styles created. For more information about nonces, see Nonces in MDN's Content Security Policy (CSP) documentation.

Additional Resources

 
Was this article helpful?
8 out of 13 found this helpful