Brand Hub
Brand Hub is a CI HUB feature that lets users browse structured brand assets — logos, color palettes, fonts, and branded imagery — organized by category. It surfaces your platform's brand guidelines directly in creative tools.
When to implement
Implement Brand Hub if your platform has:
- A structured brand asset library with categorized content (logos, icons, color swatches)
- Assets tagged or organized by brand category type
If your platform is a general-purpose DAM without brand-specific structure, you can skip Brand Hub — it's fully optional.
Enabling Brand Hub
Set supportsBrandHub: true in your integration capabilities:
defineIntegration({
capabilities: {
category: CategoryEnum.DAM,
supportsBrandHub: true,
// ...
},
// ...
})This tells CI HUB to show the Brand Hub tab and call getBrandConfig and getBrandAssets.
Brand asset tagging
Brand Hub uses a tagging convention to categorize assets. Assets in your platform are tagged with two types of prefixes:
| Prefix | Meaning | Example tag |
|---|---|---|
CIH_BCT_ | Brand Category Type | CIH_BCT_logo, CIH_BCT_color |
CIH_BCN_ | Brand Category Name | CIH_BCN_Primary, CIH_BCN_Secondary |
Your platform stores these as regular tags on assets. When CI HUB requests brand assets, filter by these prefixes.
getBrandConfig
Returns the brand structure — what categories and sub-categories of brand assets exist. All parameters come from requestData.query:
getBrandConfig: async (locals, requestData) => {
try {
const brandAssets = await callApi(locals, '/api/assets', {
params: { tags: 'CIH_BCT_' },
})
const categories = extractBrandCategories(brandAssets)
return send({
categories,
})
} catch (error) {
return sendError(`Error fetching brand config: ${error}`, 400)
}
},getBrandAssets
Returns assets for a specific brand category. The folderId and categoryType come from requestData.query:
getBrandAssets: async (locals, requestData) => {
const { folderId, categoryType } = requestData.query
const size = Math.min(parseInt(requestData.query.size || '25', 10), 100)
const more = parseInt(requestData.query.more || '1', 10)
try {
const results = await callApi(locals, '/api/assets', {
params: {
tags: `CIH_BCN_${folderId}`,
size,
page: more,
},
})
return send({
categoryType,
assets: results.items.map(mapToAsset),
totalAssetsCount: results.total,
more: results.hasNextPage ? more + 1 : undefined,
})
} catch (error) {
return sendError(`Error fetching brand assets: ${error}`, 400)
}
},Extracting brand categories from tags
A helper to derive the brand category tree from tagged assets:
const extractBrandCategories = (assets: any[]) => {
const typeSet = new Set<string>()
const nameMap = new Map<string, Set<string>>()
assets.forEach(asset => {
const tags: string[] = asset.tags ?? []
const type = tags.find(t => t.startsWith('CIH_BCT_'))?.replace('CIH_BCT_', '')
const name = tags.find(t => t.startsWith('CIH_BCN_'))?.replace('CIH_BCN_', '')
if (type) typeSet.add(type)
if (type && name) {
if (!nameMap.has(type)) nameMap.set(type, new Set())
nameMap.get(type)!.add(name)
}
})
return Array.from(typeSet).map(type => ({
id: type,
name: type.charAt(0).toUpperCase() + type.slice(1),
children: Array.from(nameMap.get(type) ?? []).map(name => ({
id: name,
name: name,
})),
}))
}Example - DAM queries brand collections from a search facet and filters by CIH_BCT_ prefix:
getBrandConfig: async (locals, requestData) => {
try {
const result = {
dataModelVersion: '1.0.0',
provider: locals.provider,
categories: [],
errors: []
}
const collectionTypes = (await callApi(locals, 'POST', '/api/search', null, {
defaults: 'CIHubAssetSearchConfig',
culture: defaultLanguage,
skip: 0,
take: 1,
view: 'table',
component: 819
})).facets.find(facet => facet.propertyName === 'CollectionType')?.children
if (!collectionTypes) {
return sendError('There are no Collections available')
}
const brandTypes = collectionTypes
.map(collectionType => collectionType.value)
.filter(item => item.startsWith(BRAND_TAG_PREFIXES.CATEGORY_TYPE.toLowerCase()))
const brandCollections = await callApi(locals, 'POST', '/api/search', null, {
defaults: 'CIHubAssetSearchConfig',
culture: defaultLanguage,
skip: 0,
take: 1000,
view: 'table',
component: 819,
filters: [{
name: 'properties.invariant.collectiontype',
label: 'Collection type',
type: 'InFilter',
values: brandTypes,
operator: 'AnyOf',
group: 'properties.invariant.collectiontype',
visible: true
}]
})
result.categories = brandCollections.items.map(folder => ({
folderId: `${folder.id}`,
title: folder.properties.CollectionName,
categoryType: folder.properties.CollectionType.identifier
.replace(BRAND_TAG_PREFIXES.CATEGORY_TYPE, '')
})).filter(collection => ['colors', 'images'].includes(collection.categoryType))
return send(result)
} catch (error) {
return sendError('Error getting folders and items:', error)
}
},Brand asset metadata
Brand assets use the same values array as regular assets. See Metadata Values for grouping patterns and value types.
Brand Hub is additive. Start without it and add it later once your core asset browsing works. It requires no changes to your existing handlers.