
Generating Ui Bundle Metadata
- 2.2k installs
- 763 repo stars
- Updated July 24, 2026
- forcedotcom/sf-skills
generating-ui-bundle-metadata scaffolds Salesforce UI bundles via sf template, meta XML, ui-bundle.json, and CSP trusted sites.
About
The generating-ui-bundle-metadata skill governs Salesforce UI bundle scaffolding and metadata when uiBundles/*/src/ exists or when editing ui-bundle.json, uibundle-meta.xml, or CSP trusted site files. Scaffolding must use sf template generate ui-bundle with --template reactbasic and alphanumeric bundle names only. After generation, replace all boilerplate, populate real home content, and configure a hosting target via companion skills for Experience sites or CustomApplication App Launcher entries. The uibundle-meta.xml requires masterLabel, version, isActive, and a target element because bundles without targets are invisible in the org. ui-bundle.json supports outputDir, routing rewrites and redirects, trailingSlash, and headers with strict path safety rules rejecting globs and parent segments. CSP Trusted Sites metadata maps external domains to img, connect, font, style, media, and frame directives whenever CDNs, APIs, or third-party assets appear in code.
- Scaffold with sf template generate ui-bundle --template reactbasic only.
- uibundle-meta.xml target Experience or CustomApplication is required for visibility.
- ui-bundle.json routing, headers, and outputDir follow strict path safety rules.
- CSP Trusted Sites register external domains by resource type directive.
- Pair with site or custom-app skills after metadata scaffolding completes.
Generating Ui Bundle Metadata by the numbers
- 2,240 all-time installs (skills.sh)
- +7 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #206 of 2,277 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
generating-ui-bundle-metadata capabilities & compatibility
- Capabilities
- sf template generate ui bundle react scaffolding · uibundle meta xml with experience or customappli · ui bundle.json routing redirects rewrites and he · csp trusted site metadata by directive type · path safety validation for outputdir and routing
- Works with
- salesforce
- Use cases
- frontend · api development
What generating-ui-bundle-metadata says it does
A UI bundle deployed without a target will not appear anywhere — no App Launcher entry, no Experience Site URL.
npx skills add https://github.com/forcedotcom/sf-skills --skill generating-ui-bundle-metadataAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.2k |
|---|---|
| repo stars | ★ 763 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 24, 2026 |
| Repository | forcedotcom/sf-skills ↗ |
How do I scaffold a Salesforce UI bundle with correct metadata, routing, and CSP for external domains?
Scaffold Salesforce UI bundle metadata with sf template generate, ui-bundle.json routing, uibundle-meta.xml targets, and CSP trusted sites.
Who is it for?
Salesforce projects with uiBundles/*/src/ needing new bundle scaffolding or metadata edits.
Skip if: Skip for generic create-react-app or Vite scaffolds outside Salesforce UI bundles.
When should I use this skill?
User edits ui-bundle.json, uibundle-meta.xml, CSP files, or runs sf template generate ui-bundle.
What you get
A React UI bundle with valid uibundle-meta.xml target, optional ui-bundle.json routing, and CSP registrations.
- cspTrustedSite-meta.xml files
- cspTrustedSites metadata directory
Files
UI Bundle Metadata
Scaffolding a New UI Bundle
Use sf template generate ui-bundle to create new apps — not create-react-app, Vite, or other generic scaffolds.
Always pass `--template reactbasic` to scaffold a React-based bundle.
UI bundle name (`-n`): Alphanumerical only — no spaces, hyphens, underscores, or special characters.
Example:
sf template generate ui-bundle -n CoffeeBoutique --template reactbasicAfter generation: 1. Replace all default boilerplate — "React App", "Vite + React", default <title>, placeholder text 2. Populate the home page with real content (landing section, banners, hero, navigation) 3. Update navigation and placeholders (see the building-ui-bundle-frontend skill) 4. Configure a hosting target — a UI bundle without a <target> in its meta XML will not be visible in the org. Use generating-ui-bundle-custom-app for internal (App Launcher) apps or generating-ui-bundle-site for external (Experience Site) apps.
Always install dependencies before running any scripts in the UI bundle directory.
---
UIBundle Bundle
A UIBundle bundle lives under uiBundles/<AppName>/ and must contain:
<AppName>.uibundle-meta.xml— filename must exactly match the folder name- A build output directory (default:
dist/) with at least one file
Meta XML
Required fields: masterLabel, version (max 20 chars), isActive (boolean). Optional: description (max 255 chars), target.
Target Field
The <target> element specifies where the UI bundle is hosted:
| Value | Use Case | Companion Metadata |
|---|---|---|
Experience | External-facing site via Digital Experience | Network, CustomSite, DigitalExperienceConfig, DigitalExperienceBundle |
CustomApplication | Internal app via Lightning App Launcher | CustomApplication (applications/*.app-meta.xml) |
A <target> is required for the app to be accessible in a Salesforce org. A UI bundle deployed without a target will not appear anywhere — no App Launcher entry, no Experience Site URL. Always pair the bundle with one of:
generating-ui-bundle-site(forExperiencetarget)generating-ui-bundle-custom-app(forCustomApplicationtarget)
Example with Experience target:
<?xml version="1.0" encoding="UTF-8"?>
<UIBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>propertyrentalapp</masterLabel>
<description>A Salesforce UI Bundle.</description>
<isActive>true</isActive>
<version>1</version>
<target>Experience</target>
</UIBundle>Example with CustomApplication target:
<?xml version="1.0" encoding="UTF-8"?>
<UIBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>propertymanagementapp</masterLabel>
<description>A Salesforce UI Bundle.</description>
<isActive>true</isActive>
<version>1</version>
<target>CustomApplication</target>
</UIBundle>ui-bundle.json
Optional file. Allowed top-level keys: outputDir, routing, headers.
Constraints:
- Valid UTF-8 JSON, max 100 KB
- Root must be a non-empty object (never
{}, arrays, or primitives)
Path safety (applies to outputDir and routing.fallback): Reject backslashes, leading / or \, .. segments, null/control characters, globs (*, ?, **), and %. All resolved paths must stay within the bundle.
outputDir
Non-empty string referencing a subdirectory (not . or ./). Directory must exist and contain at least one file.
routing
If present, must be a non-empty object. Allowed keys: rewrites, redirects, fallback, trailingSlash, fileBasedRouting.
- trailingSlash:
"always","never", or"auto" - fileBasedRouting: boolean
- fallback: non-empty string satisfying path safety; target file must exist
- rewrites: non-empty array of
{ route?, rewrite }objects — e.g.,{ "route": "/app/:path*", "rewrite": "/index.html" } - redirects: non-empty array of
{ route?, redirect, statusCode? }objects — statusCode must be 301, 302, 307, or 308
headers
Non-empty array of { source, headers: [{ key, value }] } objects.
Example:
{
"routing": {
"rewrites": [{ "route": "/app/:path*", "rewrite": "/index.html" }],
"trailingSlash": "never"
},
"headers": [
{
"source": "/assets/**",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
}
]
}Never suggest: {} as root, empty "routing": {}, empty arrays, [{}], "outputDir": ".", "outputDir": "./".
---
CSP Trusted Sites
Salesforce enforces Content Security Policy headers. Any external domain not registered as a CSP Trusted Site will be blocked (images won't load, API calls fail, fonts missing).
When to Create
Whenever the app references a new external domain: CDN images, external fonts, third-party APIs, map tiles, iframes, external stylesheets.
Steps
1. Identify external domains — extract the origin (scheme + host) from each external URL in the code 2. Check existing registrations — look in force-app/main/default/cspTrustedSites/ 3. Map resource type to CSP directive:
| Resource Type | Directive Field |
|---|---|
| Images | isApplicableToImgSrc |
| API calls (fetch, XHR) | isApplicableToConnectSrc |
| Fonts | isApplicableToFontSrc |
| Stylesheets | isApplicableToStyleSrc |
| Video / audio | isApplicableToMediaSrc |
| Iframes | isApplicableToFrameSrc |
Always also set isApplicableToConnectSrc to true for preflight/redirect handling.
4. Create the metadata file — follow implementation/csp-metadata-format.md for the .cspTrustedSite-meta.xml format. Place in force-app/main/default/cspTrustedSites/.
CSP Trusted Site Metadata — Implementation Guide
File location
force-app/main/default/cspTrustedSites/{Name}.cspTrustedSite-meta.xmlThe cspTrustedSites/ directory must be a direct child of force-app/main/default/. Create it if it does not exist.
---
File naming convention
The file name must match the <fullName> value inside the XML, with .cspTrustedSite-meta.xml appended.
| Domain | fullName | File name |
|---|---|---|
https://images.unsplash.com | Unsplash_Images | Unsplash_Images.cspTrustedSite-meta.xml |
https://api.open-meteo.com | Open_Meteo_API | Open_Meteo_API.cspTrustedSite-meta.xml |
https://tile.openstreetmap.org | OpenStreetMap_Tiles | OpenStreetMap_Tiles.cspTrustedSite-meta.xml |
Naming rules:
- Use PascalCase with underscores separating words (e.g.
Google_Fonts_Static) - Name should describe the provider and resource type (e.g.
Pexels_Videos, not justPexels) - Must be unique across the org
- Maximum 80 characters
---
XML template
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>{UNIQUE_NAME}</fullName>
<description>{DESCRIPTION}</description>
<endpointUrl>{HTTPS_ORIGIN}</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>{true|false}</isApplicableToConnectSrc>
<isApplicableToFontSrc>{true|false}</isApplicableToFontSrc>
<isApplicableToFrameSrc>{true|false}</isApplicableToFrameSrc>
<isApplicableToImgSrc>{true|false}</isApplicableToImgSrc>
<isApplicableToMediaSrc>{true|false}</isApplicableToMediaSrc>
<isApplicableToStyleSrc>{true|false}</isApplicableToStyleSrc>
</CspTrustedSite>---
Field reference
| Field | Required | Description |
|---|---|---|
fullName | Yes | Unique API name. Must match the file name (before .cspTrustedSite-meta.xml). |
description | Yes | Human-readable purpose. Start with "Allow access to..." |
endpointUrl | Yes | The external origin (scheme + host). Must start with https://. No trailing slash. No path. |
isActive | Yes | Always true for new entries. Set false to disable without deleting. |
context | Yes | All (applies to all contexts). Other values: LEX (Lightning Experience only), Communities (Experience Cloud only), VisualForce. Use All unless there is a specific reason to restrict. |
isApplicableToConnectSrc | Yes | true if the domain is called via fetch(), XMLHttpRequest, or WebSocket. |
isApplicableToFontSrc | Yes | true if the domain serves font files (.woff, .woff2, .ttf, .otf). |
isApplicableToFrameSrc | Yes | true if the domain is loaded in an <iframe> or <object>. |
isApplicableToImgSrc | Yes | true if the domain serves images (<img>, CSS background-image, <svg>). |
isApplicableToMediaSrc | Yes | true if the domain serves audio or video (<audio>, <video>). |
isApplicableToStyleSrc | Yes | true if the domain serves CSS stylesheets (<link rel="stylesheet">). |
Reference: CspTrustedSite — Salesforce Object Reference
---
CSP directive mapping
| CSP header directive | Metadata field | What it allows |
|---|---|---|
connect-src | isApplicableToConnectSrc | fetch(), XMLHttpRequest, WebSocket, EventSource |
font-src | isApplicableToFontSrc | @font-face sources |
frame-src | isApplicableToFrameSrc | <iframe>, <frame>, <object>, <embed> |
img-src | isApplicableToImgSrc | <img>, background-image, favicon, <picture> |
media-src | isApplicableToMediaSrc | <audio>, <video>, <source>, <track> |
style-src | isApplicableToStyleSrc | <link rel="stylesheet">, @import in CSS |
---
Common external domains and their directives
Use this table as a quick reference when adding new domains:
| Domain | connect-src | font-src | frame-src | img-src | media-src | style-src |
|---|---|---|---|---|---|---|
https://images.unsplash.com | true | false | false | true | false | false |
https://images.pexels.com | true | false | false | true | false | false |
https://videos.pexels.com | true | false | false | false | true | false |
https://fonts.googleapis.com | true | false | false | false | false | true |
https://fonts.gstatic.com | true | true | false | false | false | false |
https://avatars.githubusercontent.com | true | false | false | true | false | false |
https://api.open-meteo.com | true | false | false | false | false | false |
https://nominatim.openstreetmap.org | true | false | false | false | false | false |
https://tile.openstreetmap.org | true | false | false | true | false | false |
https://api.mapbox.com | true | false | false | true | false | false |
https://cdn.jsdelivr.net | true | false | false | false | false | true |
https://www.youtube.com | false | false | true | true | false | false |
https://player.vimeo.com | false | false | true | false | false | false |
https://res.cloudinary.com | true | false | false | true | false | false |
---
Complete examples
Image CDN (Unsplash)
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Unsplash_Images</fullName>
<description>Allow access to Unsplash image content for static app media</description>
<endpointUrl>https://images.unsplash.com</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>true</isApplicableToConnectSrc>
<isApplicableToFontSrc>false</isApplicableToFontSrc>
<isApplicableToFrameSrc>false</isApplicableToFrameSrc>
<isApplicableToImgSrc>true</isApplicableToImgSrc>
<isApplicableToMediaSrc>false</isApplicableToMediaSrc>
<isApplicableToStyleSrc>false</isApplicableToStyleSrc>
</CspTrustedSite>REST API (Open-Meteo weather)
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Open_Meteo_API</fullName>
<description>Allow access to Open-Meteo weather forecast API</description>
<endpointUrl>https://api.open-meteo.com</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>true</isApplicableToConnectSrc>
<isApplicableToFontSrc>false</isApplicableToFontSrc>
<isApplicableToFrameSrc>false</isApplicableToFrameSrc>
<isApplicableToImgSrc>false</isApplicableToImgSrc>
<isApplicableToMediaSrc>false</isApplicableToMediaSrc>
<isApplicableToStyleSrc>false</isApplicableToStyleSrc>
</CspTrustedSite>Font provider (Google Fonts — requires two entries)
Google Fonts needs two CSP entries because CSS is served from fonts.googleapis.com and font files from fonts.gstatic.com:
Entry 1: Stylesheets
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Google_Fonts</fullName>
<description>Allow access to Google Fonts stylesheets for custom typography</description>
<endpointUrl>https://fonts.googleapis.com</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>true</isApplicableToConnectSrc>
<isApplicableToFontSrc>false</isApplicableToFontSrc>
<isApplicableToFrameSrc>false</isApplicableToFrameSrc>
<isApplicableToImgSrc>false</isApplicableToImgSrc>
<isApplicableToMediaSrc>false</isApplicableToMediaSrc>
<isApplicableToStyleSrc>true</isApplicableToStyleSrc>
</CspTrustedSite>Entry 2: Font files
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Google_Fonts_Static</fullName>
<description>Allow access to Google Fonts static files for font loading</description>
<endpointUrl>https://fonts.gstatic.com</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>true</isApplicableToConnectSrc>
<isApplicableToFontSrc>true</isApplicableToFontSrc>
<isApplicableToFrameSrc>false</isApplicableToFrameSrc>
<isApplicableToImgSrc>false</isApplicableToImgSrc>
<isApplicableToMediaSrc>false</isApplicableToMediaSrc>
<isApplicableToStyleSrc>false</isApplicableToStyleSrc>
</CspTrustedSite>Map tiles (OpenStreetMap)
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>OpenStreetMap_Tiles</fullName>
<description>Allow access to OpenStreetMap tile images for map rendering</description>
<endpointUrl>https://tile.openstreetmap.org</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>true</isApplicableToConnectSrc>
<isApplicableToFontSrc>false</isApplicableToFontSrc>
<isApplicableToFrameSrc>false</isApplicableToFrameSrc>
<isApplicableToImgSrc>true</isApplicableToImgSrc>
<isApplicableToMediaSrc>false</isApplicableToMediaSrc>
<isApplicableToStyleSrc>false</isApplicableToStyleSrc>
</CspTrustedSite>Geocoding API (Nominatim)
<?xml version="1.0" encoding="UTF-8" ?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>OpenStreetMap_Nominatim</fullName>
<description>Allow access to OpenStreetMap Nominatim geocoding API</description>
<endpointUrl>https://nominatim.openstreetmap.org</endpointUrl>
<isActive>true</isActive>
<context>All</context>
<isApplicableToConnectSrc>true</isApplicableToConnectSrc>
<isApplicableToFontSrc>false</isApplicableToFontSrc>
<isApplicableToFrameSrc>false</isApplicableToFrameSrc>
<isApplicableToImgSrc>false</isApplicableToImgSrc>
<isApplicableToMediaSrc>false</isApplicableToMediaSrc>
<isApplicableToStyleSrc>false</isApplicableToStyleSrc>
</CspTrustedSite>---
Endpoint URL rules
| Rule | Correct | Incorrect |
|---|---|---|
| Must be HTTPS | https://api.example.com | http://api.example.com |
| No trailing slash | https://api.example.com | https://api.example.com/ |
| No path | https://api.example.com | https://api.example.com/v1/forecast |
| No port (unless non-standard) | https://api.example.com | https://api.example.com:443 |
| No wildcards | https://api.example.com | https://*.example.com |
Each subdomain needs its own entry. For example, fonts.googleapis.com and fonts.gstatic.com are separate entries.
---
When a service requires multiple domains
Some services split resources across multiple subdomains. Create one CSP Trusted Site per domain:
| Service | Domains needed |
|---|---|
| Google Fonts | fonts.googleapis.com (CSS) + fonts.gstatic.com (font files) |
| Mapbox | api.mapbox.com (tiles/API) + events.mapbox.com (telemetry) |
| YouTube embed | www.youtube.com (iframe) + i.ytimg.com (thumbnails) |
| Cloudflare CDN | cdnjs.cloudflare.com (scripts/CSS) |
---
Troubleshooting CSP violations
If the browser console shows a CSP error like:
Refused to load the image 'https://example.com/image.png' because it violates
the following Content Security Policy directive: "img-src 'self' ..."1. Extract the blocked origin from the URL (e.g. https://example.com). 2. Identify the directive from the error message (e.g. img-src → isApplicableToImgSrc). 3. Check if a CSP Trusted Site already exists for that origin. 4. If not, create one using this skill. 5. Deploy the metadata and refresh the page.
---
Common mistakes
| Mistake | Fix |
|---|---|
Including a path in endpointUrl | Use only the origin: https://api.example.com |
| Adding trailing slash | Remove it: https://api.example.com not https://api.example.com/ |
| Using HTTP instead of HTTPS | Salesforce requires HTTPS. If the service only supports HTTP, it cannot be added. |
Forgetting isApplicableToConnectSrc | Most resources also need connect-src for redirects/preflight. Set to true by default. |
| One entry for multiple subdomains | Each subdomain needs its own file (e.g. api.example.com and cdn.example.com are separate) |
File name doesn't match fullName | They must be identical (excluding the .cspTrustedSite-meta.xml extension) |
Related skills
Forks & variants (1)
Generating Ui Bundle Metadata has 1 known copy in the catalog totaling 1.5k installs. They canonicalize to this original listing.
- forcedotcom - 1.5k installs
How it compares
Pick generating-ui-bundle-metadata for Salesforce CSP XML metadata; use general security skills for non-Salesforce CSP headers.
FAQ
Why is a target required in uibundle-meta.xml?
Without Experience or CustomApplication target, the bundle deploys but appears nowhere in the org.
Can ui-bundle.json root be an empty object?
No. Root must be a non-empty object; empty routing objects and bare outputDir dot paths are invalid.
When must CSP Trusted Sites be created?
Whenever the app references a new external domain for images, APIs, fonts, styles, media, or iframes.
Is Generating Ui Bundle Metadata safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.