Add images, logos & favicons
Re-host any image from a URL onto the Productised CDN, or upload reusable brand images as variables to drop into any page.
There are two ways to get images into your products: upload_image (re-host an image from a URL, great for scraping a customer's logo) and image variables (upload reusable brand assets in the app and reference them anywhere as {{ custom:key }}). This page covers both.
Why re-host?
You could embed a third-party URL directly (<img src="https://customer-site.com/logo.png">), but it's fragile:
- The customer redesigns their site — the URL 404s, your branding breaks
- The host blocks hotlinking — the image silently stops loading
- A swapped source could inject something unexpected into your product
Re-hosting snapshots the asset onto your CDN: durable, owned, optimisable, served from Productised's domain. The customer's site can change without affecting your product.
The tool: upload_image
upload_image accepts an image two ways:
source_url (preferred)
A direct link to an image. The server downloads it (with SSRF guards), re-hosts it, returns a permanent CDN URL. This is what Claude uses for scraped logos.
base64_data
Raw image bytes encoded as base64. Useful when an image isn't reachable by URL — but uncommon, since Claude works in text/JSON.
Supported types: jpeg, png, gif, webp, svg, ico. Max 10 MB via the connector (the in-app uploader caps at 5 MB). For a logo, a square PNG or SVG at least 256×256px renders crisply everywhere it's used — chat header, footer badge, and social share cards.
The canonical "brand my product from a website" flow
"Take the logo from acme.com, set it as the branding for my AI Readiness Scorecard, and use the favicon for the page SEO."
Claude does this:
Web fetch acme.com
Claude's built-in web fetch reads the homepage, locates the <img class="logo"> and <link rel="icon"> URLs.
Re-host the logo
Claude calls upload_image({ source_url: "https://acme.com/logo.png", filename: "acme-logo.png", product_id: "..." }). The connector downloads, validates, re-hosts. Returns: https://assets.productised.ai/<tenant>/product-assets/<product>/<ts>-acme-logo.png.
Re-host the favicon
Same call for the favicon (often .ico, also supported).
Apply
Claude calls update_branding({ logo_url: "..." }) and update_seo({ favicon: "..." }) with the new CDN URLs. Branding applied.
All four steps happen in one round-trip. The customer never uploads anything.
Reusable brand images (image variables)
For images you'll use across many pages — your logo, headshot, product photos — upload them once as image variables in the app (Settings → Variables, switch the type to Image). Each becomes a named {{ custom:key }} token. See Variables for the full walkthrough.
When you build a page in Claude, the connector sees your uploaded images (via get_variables, which returns an images list) and offers them — you don't have to recall the key:
"Design my results page and put my logo in the header."
Claude drops the token straight into the tag:
<img src="{{ custom:brand_logo }}" alt="Logo" />
Because the page uses the token (not a baked-in URL), swapping the image in Settings updates every page at once. This is the recommended way to put your own files on a page — see the limitation below.
Where to use the returned URL
The CDN URL upload_image returns can be used anywhere an image URL is accepted:
| Tool | Field | Use case |
|---|---|---|
update_branding | logo_url | The logo in the chat header |
update_seo | favicon | The browser tab icon |
update_seo | og_image | Social share card image |
update_page / set_welcome_html | <img src> in HTML | Inline images in result or landing pages |
Security guards
The connector's image fetch isn't a wide-open proxy. It enforces:
- HTTPS / HTTP only. No
file://,data:, orjavascript:URLs. - No internal addresses. Loopback (
127.0.0.1,localhost), private ranges (10.*,192.168.*,172.16-31.*), and cloud metadata (169.254.169.254) are blocked — a standard SSRF guard. - Size cap. Anything over 10 MB is rejected.
- Content-type validation. The fetched response must be one of the allowed image types, sniffed from the response header or URL extension.
- Timeout. The fetch aborts after 12s so a slow source can't hang the conversation.
The download and re-host happen on the Productised side (via the app's storage credentials), so the MCP server itself never touches storage directly — single source of truth, one credential set.
Limitations
- No binary upload from the Claude chat. You can't drag a file into Claude and have it arrive at Productised — MCP is a text/JSON protocol. To use your own image on a page, either upload it as an image variable in the app and reference
{{ custom:key }}, or give Claude a public URL forupload_image. - No transformations. The image is stored as-fetched. If you need a resize, crop, or format conversion, do it before uploading (or ask Claude to fetch a specific size from the source site if it offers multiple).
- No deletion via the connector. Old uploads stay on the CDN until you remove them via the app. They're scoped to your tenant/product folder.
Common asks
Brand a product from a customer's site:
"Use the branding from beautifulagency.com — logo, favicon, og image, and pick the brand colour from their site."
Pull a single asset:
"Re-host the image at https://example.com/hero.jpg and use it as the landing page banner."
Use your own uploaded logo on a page:
"Use my logo from Settings in the result page header."
Update branding on every product in my workspace:
"Apply the logo I just uploaded to all my products."
Claude calls list_products, iterates, calls update_branding for each. Done in one message.