Support/Builder Guide/Host SaaS CSS, logos, images, and design assets

Builder Guide

Host SaaS CSS, logos, images, and design assets

Upload app-scoped assets, organize virtual folders, publish validated CSS, and use stable public asset URLs in pages and React templates.

Workspace
App Assets
Public base
assets.buildwithhq.com
Blocked
.dll, .com, .exe
Storage root
Operator configured

App Assets is the design-file library for one SaaS application. It stores logos, images, fonts, videos, PDFs, downloads, and a validated app stylesheet without putting file bytes or server paths in page JSON. Public files receive an immutable URL under that SaaS app's identity.

Uploads are private by default. Public delivery requires an explicit selection and should be used only when a browser or published stylesheet must load the asset without an authenticated content request.

Automate assets through the Developer API

A trusted developer backend has the same three styling layers as the dashboard: app-wide theme, shared assets, and page drafts/publishing. Use GET/PUT /v1/apps/{saasAppId}/theme with themes.read/themes.write for the theme, validated --runtime-* variables, and base design tokens. Use assets.read/assets.write for the asset routes. Page layout and page-level tokens use the existing page-draft, validation, history, and publish routes.

const api = new BuildWithHQConnector({{ saasAppId, credential }});
await api.uploadAsset({{
  file: new Blob([css], {{ type: "text/css" }}),
  fileName: "theme.css",
  folderPath: "theme",
  assetType: "stylesheet",
  isPublic: true,
}});
Important

The live app credential belongs only in a trusted server or secured automation host. Browser React should receive the resulting public asset URL, never the credential.

Note

Compile Tailwind locally in the React project, then upload the production CSS. The API does not execute npm, Tailwind plugins, arbitrary JavaScript, or customer build scripts. A headless React host can use its own CSS or link the returned public stylesheet URL.

The API never accepts a database, server, storage root, storage key, tenant account, or connection string. The app boundary is derived from the credential, and the database principal has execute-only access to reviewed asset procedures with no table or DDL permissions.

Upload and organize an asset

  1. Sign in to the SaaS as an account owner and choose Assets in the application header.
  2. Select a file and optionally enter a virtual folder such as brand/logos, theme/fonts, or product/screenshots.
  3. Uploads start private. Select Public design asset only when a browser page or stylesheet must load the file directly.
  4. Choose Upload, then copy the URL shown on the asset card.
Note

The folder is a virtual label inside the SaaS. Slashes are normalized to a stable relative path. It cannot select a drive, network share, server directory, or another SaaS app.

An explicitly public file uses:

https://assets.buildwithhq.com/{saasAppId}/{assetId}

The server assigns both GUIDs. Do not construct an asset URL from a database name, account ID, user ID, filename, or storage path.

Publish custom CSS for one SaaS

  1. Open Custom CSS in App Assets and paste UTF-8 CSS using the existing --runtime-* tokens and narrowly scoped selectors.
  2. Choose Preview CSS and review normal, loading, empty, error, dialog, desktop, tablet, and mobile states.
  3. Choose Publish CSS. The server validates it and saves a new immutable public theme.css under the virtual theme folder.
  4. The runtime loads the newest public stylesheet once per signed-in SaaS identity; ordinary page navigation does not reload it.

A stylesheet url(...) may use a fragment, relative application path, or the same SaaS app's asset prefix. Use exact public URLs for fonts and background images.

Important

Published CSS rejects imports, executable URLs, scriptable legacy expressions, embedded markup, and remote or cross-app asset URLs. CSS cannot create an API route, grant a permission, or replace a native module action.

Use assets in pages and React

  • Use the public URL in a registered logo, image, download, poster, or bounded asset property.
  • Pass the URL as data to repository-maintained React; page JSON must never become an arbitrary import path.
  • Keep meaningful alternative text and responsive dimensions in the owning component.
Important

Current template-pack members do not copy asset bytes or remap source-SaaS URLs into a newly installed SaaS. Asset-dependent marketplace templates are not self-contained until exact-version asset packaging and destination remapping are implemented.

File and delivery rules

FileAccepted?Public behavior
DLL, COM, EXENoRejected before storage
Validated CSSYesRendered as text/css
PNG, JPEG, GIF, WebP, AVIFYesRendered inline
MP4, WebM, WOFF, WOFF2, PDFYesRendered inline
HTML, SVG, scripts, archives, source, or unknownYesDownloaded as an inert binary attachment with nosniff and sandbox policy

Uploads retain the 25 MiB limit; CSS is limited to 512 KiB. Stored bytes are SHA-256 hashed. Removing an asset makes its URL unavailable rather than reusing its identity. Public delivery resolves the active app and retrieves only explicitly public metadata; the browser receives no storage key, path, database coordinate, or credential.

Troubleshooting

SymptomCheck
Upload rejectedCheck the extension, simple filename, virtual-folder traversal, and 25 MiB limit.
CSS rejectedRemove imports, executable or remote URLs, embedded markup, and unsupported encoding; remain below 512 KiB.
Public URL returns 404Confirm the asset is public, active, not removed, and belongs to the URL's SaaS app.
Asset host cannot connectHave the operator verify DNS, TLS, reverse proxy, and preserved Host routing.
New CSS is absentConfirm publish succeeded, reload once, and inspect link#bwhq-published-theme-css.

Operators should continue with Deploy the SaaS asset domain and storage root. Template maintainers should also read Apply a TailAdmin-style design.

Compare all six styling approaches in Support for React.

Capability review: 2026-09-14. For exact current technical availability, use the generated API Map and first-class module inventory.