---
title: Render untrusted content as text
description: >-
  Render every value that you didn't write yourself as text, using an API that
  can't produce markup, so injected content can't run as code.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/security/backend/render-untrusted-content-as-text
  md: >-
    https://shopify.dev/docs/apps/build/security/backend/render-untrusted-content-as-text.md
---

# Render untrusted content as text

Render every value that you didn't write yourself as text, using an API that can't produce markup.

***

## Why

Cross-site scripting (XSS) happens when content that an attacker controls is rendered as markup or code. The content can arrive through any field your app renders: a product title or description, a variant value, a metafield, a cart line item property, a discount code, a search query, an uploaded file name, or any setting that you don't control. A script that runs this way can read sessions, tokens, and the personal and payment information entered on the page, act as a logged-in merchant in the Shopify admin, or change a storefront.

Shopify serves a Content Security Policy (CSP) that limits what a browser loads. It's permissive enough for apps and themes to work, and it doesn't restrict markup that your own code renders into the page, so it's a backstop rather than a control.

***

## How

Search your code for the sinks that execute untrusted input, and replace them:

```javascript
// Avoid: these treat the value as markup.
element.innerHTML = untrustedValue;
element.insertAdjacentHTML('beforeend', untrustedValue);
document.write(untrustedValue);
$(element).html(untrustedValue);


// Use: this can produce only text.
element.textContent = untrustedValue;
```

`textContent` covers text. Handle code, HTML input, and URLs separately:

* Never execute as code a string supplied by a store owner, a user, or any other source outside your control. Configuration and customization have better answers: structured settings, a fixed set of options, or a sandboxed extension point.
* If your product needs to accept HTML, then sanitize it on your server with a well-maintained sanitizer and a strict allowlist of tags and attributes.
* Validate URLs. Allow only the schemes you need, which is normally just `https:`, and reject `javascript:`, unexpected `data:` URLs, and protocol-relative URLs.

For the Liquid side of this practice, see [Escape every value for its context](https://shopify.dev/docs/apps/build/security/storefront/escape-every-value-for-its-context).

***
