Créer des Content Cards
Cet article présente l’approche de base pour mettre en œuvre des Content Cards personnalisées, ainsi que trois cas d’usage courants. Il part du principe que vous avez déjà lu les autres articles du guide de personnalisation des Content Cards pour comprendre ce qui peut être fait par défaut et ce qui nécessite du code personnalisé. Il est particulièrement utile de comprendre comment enregistrer les analyses pour vos Content Cards personnalisées.

Vous utilisez des Content Cards pour des messages de type bannière ? Essayez les Bannières— parfaites pour les messages in-app et web intégrés et persistants.
Créer une carte
Étape 1 : Créer une interface utilisateur personnalisée
Commencez par créer votre composant HTML personnalisé qui sera utilisé pour afficher les cartes.
Commencez par créer votre propre fragment personnalisé. Le ContentCardsFragment par défaut est uniquement conçu pour gérer nos types de Content Cards par défaut, mais constitue un bon point de départ.
Commencez par créer votre propre composant de contrôleur de vue personnalisé. Le BrazeContentCardUI.ViewController par défaut est uniquement conçu pour gérer nos types de Content Cards par défaut, mais constitue un bon point de départ.
Étape 2 : S’abonner aux mises à jour des cartes
Enregistrez une fonction de rappel pour vous abonner aux mises à jour de données lorsque les cartes sont actualisées. Vous pouvez analyser les objets Content Card et extraire leurs données de payload, telles que title, cardDescription et imageUrl, puis utiliser les données du modèle résultant pour remplir votre interface utilisateur personnalisée.
Pour obtenir les modèles de données Content Card, abonnez-vous aux mises à jour des Content Cards. Accordez une attention particulière aux propriétés suivantes :
id: Représente la chaîne de caractères d’identifiant de la Content Card. Il s’agit de l’identifiant unique utilisé pour enregistrer les analyses à partir des Content Cards personnalisées.extras: Englobe toutes les paires clé-valeur provenant du tableau de bord de Braze.
Toutes les propriétés en dehors de id et extras sont facultatives à analyser pour les Content Cards personnalisées. Pour plus d’informations sur le modèle de données, consultez l’article d’intégration de chaque plateforme : Android, iOS, Web.
Utilisez subscribeToContentCardsEvents pour recevoir les événements Content Card. Le SDK appelle votre gestionnaire avec un objet événement. Utilisez un switch sur event.type pour gérer chaque type d’événement. Pour plus d’informations sur les valeurs d’événement, consultez Abonnements aux événements.
import * as braze from "@braze/web-sdk";
function renderCards(cards) {
// For example:
cards.forEach(card => {
if (card.isControl) {
// Do not display the control card, but remember to call `logContentCardImpressions([card])`
}
else if (card instanceof braze.ClassicCard || card instanceof braze.CaptionedImage) {
// Use `card.title`, `card.imageUrl`, etc.
}
else if (card instanceof braze.ImageOnly) {
// Use `card.imageUrl`, etc.
}
});
}
// - Available in version 7.0.0+
const subscriptionId = braze.subscribeToContentCardsEvents((event) => {
switch (event.type) {
case braze.ChannelEventType.CACHE_REPLAY:
// Sent once, right away, with the cards that are already cached.
// Render them now instead of waiting for the network.
renderCards(event.cacheSnapshot.contentCards.cards);
break;
case braze.ChannelEventType.CACHE_LOAD:
// The cache changed without a refresh, such as after changeUser().
// The snapshot can be empty, so clear cards from the previous user.
renderCards(event.cacheSnapshot.contentCards.cards);
break;
case braze.ChannelEventType.DATA_UPDATED:
// A refresh finished, even if no cards changed, or a card was dismissed.
renderCards(event.cacheSnapshot.contentCards.cards);
break;
case braze.ChannelEventType.ERROR:
switch (event.retryState) {
case braze.RetryState.SDK_WILL_RETRY:
// The SDK is retrying. Keep the current cards and wait.
break;
case braze.RetryState.INTEGRATOR_MAY_RETRY: {
// The SDK stopped retrying. Try again later, and limit how often you retry.
const delayMs = event.rateLimitedUntil
? Math.max(event.rateLimitedUntil.getTime() - Date.now(), 0)
: 30000;
setTimeout(() => braze.requestContentCardsRefresh(), delayMs);
break;
}
case braze.RetryState.DO_NOT_RETRY:
// The failure is final. For example, Content Cards are disabled for this workspace.
if (event.reason === braze.ChannelErrorReason.FEATURE_DISABLED) {
// Hide your Content Cards UI.
}
break;
}
break;
}
});
const deprecatedSubscriptionId = braze.subscribeToContentCardsUpdates((updates) => {
renderCards(updates.cards);
});
braze.openSession();
// Remove the subscription when you no longer need it
// braze.removeSubscription(subscriptionId);

Les Content Cards ne s’actualisent au démarrage de la session que si vous appelez subscribeToContentCardsEvents() (ou la méthode obsolète subscribeToContentCardsUpdates()) avant openSession(). Vous pouvez également actualiser manuellement le flux à tout moment.
Pour savoir quand chaque événement se déclenche et ce que signifient chaque raison de mise à jour, état de nouvelle tentative, action analytique et raison d’erreur, consultez Abonnements aux événements.
Utilisez subscribeToContentCardsEvents à partir du SDK Web 7.0.0. subscribeToContentCardsUpdates est le modèle précédent, obsolète depuis la version 7.0.0. Le modèle précédent ne fournit que les cartes actuelles, il ne peut donc pas vous indiquer pourquoi les cartes ont changé ni quand une actualisation a échoué.
Étape 2a : Créer une variable d’abonnement privée
Pour vous abonner aux mises à jour des cartes, déclarez d’abord une variable privée dans votre classe personnalisée pour contenir votre abonné :
// - Available in version 44.0.0+
private IEventSubscriber<ContentCardsEvent> mContentCardsEventSubscriber;
private IEventSubscriber<ContentCardsUpdatedEvent> mContentCardsUpdatedSubscriber;
Étape 2b : S’abonner aux événements
Ajoutez le code suivant pour vous abonner avec subscribeToContentCardsEvents(), généralement dans le Activity.onCreate() de votre activité Content Cards personnalisée. Effectuez un pattern-matching sur les sous-classes ContentCardsEvent dont vous avez besoin.
// - Available in version 44.0.0+
// Remove the previous subscriber before rebuilding a new one with our new activity.
Braze.getInstance(context).removeSingleSubscription(mContentCardsEventSubscriber, ContentCardsEvent.class);
mContentCardsEventSubscriber = new IEventSubscriber<ContentCardsEvent>() {
@Override
public void trigger(ContentCardsEvent event) {
if (event instanceof ContentCardsEvent.CacheReplay) {
handleCards(((ContentCardsEvent.CacheReplay) event).getCacheSnapshot());
} else if (event instanceof ContentCardsEvent.CacheLoad) {
handleCards(((ContentCardsEvent.CacheLoad) event).getCacheSnapshot());
} else if (event instanceof ContentCardsEvent.DataUpdated) {
handleCards(((ContentCardsEvent.DataUpdated) event).getCacheSnapshot());
}
}
};
Braze.getInstance(context).subscribeToContentCardsEvents(mContentCardsEventSubscriber);
Braze.getInstance(context).requestContentCardsRefresh();
// Remove the previous subscriber before rebuilding a new one with our new activity.
Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class);
mContentCardsUpdatedSubscriber = new IEventSubscriber<ContentCardsUpdatedEvent>() {
@Override
public void trigger(ContentCardsUpdatedEvent event) {
List<Card> allCards = event.getAllCards();
}
};
Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber);
Braze.getInstance(context).requestContentCardsRefresh();
private void handleCards(ContentCardsCacheSnapshot cacheSnapshot) {
List<Card> allCards = cacheSnapshot.getCards();
}
Les événements arrivent sur un thread d’arrière-plan. Basculez sur le thread principal avant de mettre à jour les vues.
Étape 2c : Se désabonner
Désabonnez-vous lorsque votre activité personnalisée n’est plus visible. Ajoutez le code suivant à la méthode du cycle de vie onDestroy() de votre activité :
// - Available in version 44.0.0+
Braze.getInstance(context).removeSingleSubscription(mContentCardsEventSubscriber, ContentCardsEvent.class);
Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class);
Étape 2a : Créer une variable d’abonnement privée
Pour vous abonner aux événements de cartes, déclarez d’abord une variable privée dans votre classe personnalisée pour contenir votre abonné :
// - Available in version 44.0.0+
private var contentCardsEventSubscriber: IEventSubscriber<ContentCardsEvent>? = null
private var contentCardsUpdatedSubscriber: IEventSubscriber<ContentCardsUpdatedEvent>? = null
Étape 2b : S’abonner aux événements
Ajoutez le code suivant pour vous abonner avec subscribeToContentCardsEvents(), généralement dans le Activity.onCreate() de votre activité Content Cards personnalisée. Effectuez un pattern-matching sur les sous-classes ContentCardsEvent dont vous avez besoin.
// - Available in version 44.0.0+
// Remove the previous subscriber before rebuilding a new one with our new activity.
Braze.getInstance(context).removeSingleSubscription(contentCardsEventSubscriber, ContentCardsEvent::class.java)
contentCardsEventSubscriber = IEventSubscriber { event ->
when (event) {
is ContentCardsEvent.CacheReplay -> handleCards(event.cacheSnapshot)
is ContentCardsEvent.CacheLoad -> handleCards(event.cacheSnapshot)
is ContentCardsEvent.DataUpdated -> handleCards(event.cacheSnapshot)
else -> {}
}
}
Braze.getInstance(context).subscribeToContentCardsEvents(contentCardsEventSubscriber)
Braze.getInstance(context).requestContentCardsRefresh()
// Remove the previous subscriber before rebuilding a new one with our new activity.
Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java)
contentCardsUpdatedSubscriber = IEventSubscriber { event ->
val allCards = event.allCards
}
Braze.getInstance(context).subscribeToContentCardsUpdates(contentCardsUpdatedSubscriber)
Braze.getInstance(context).requestContentCardsRefresh()
private fun handleCards(cacheSnapshot: ContentCardsCacheSnapshot) {
val allCards = cacheSnapshot.cards
}
Les événements arrivent sur un thread d’arrière-plan. Basculez sur le thread principal avant de mettre à jour les vues.
Étape 2c : Se désabonner
Désabonnez-vous lorsque votre activité personnalisée n’est plus visible. Ajoutez le code suivant à la méthode du cycle de vie onDestroy() de votre activité :
// - Available in version 44.0.0+
Braze.getInstance(context).removeSingleSubscription(contentCardsEventSubscriber, ContentCardsEvent::class.java)
Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java)
Pour savoir quand chaque événement se déclenche et ce que signifient chaque raison de mise à jour, état de nouvelle tentative, action analytique et raison d’erreur, consultez Abonnements aux événements.
Utilisez subscribeToContentCardsEvents à partir du SDK Android 44.0.0. subscribeToContentCardsUpdates est le modèle précédent, obsolète depuis la version 44.0.0.
Pour accéder au modèle de données Content Cards, appelez contentCards.cards sur votre instance braze.
let cards: [Braze.ContentCard] = AppDelegate.braze?.contentCards.cards
De plus, vous pouvez vous abonner aux événements Content Cards pour observer les changements de cache, les analyses et les erreurs. Vous pouvez le faire de deux façons :
- En maintenant un cancellable ; ou
- En maintenant un
AsyncStream.
Cancellable
// - Available in version 19.0.0+
// This subscription is maintained through a Braze cancellable, which will observe for events until the subscription is cancelled.
// You must keep a strong reference to the cancellable to keep the subscription active.
// The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method.
let cancellable = AppDelegate.braze?.contentCards.subscribeToEvents { [weak self] event in
switch event {
case .cacheReplay(let cacheSnapshot):
// Initial cache snapshot, delivered immediately after subscribing
break
case .cacheLoad(let cacheSnapshot):
// Cache loaded at the start of a user session (for example, after `changeUser()`)
break
case .dataUpdated(let cacheSnapshot, let reason):
// Cache changed after the initial replay
break
case .impressionEvent(let card, let action):
break
case .clickEvent(let card, let action):
break
case .dismissEvent(let card, let action):
break
case .error(let reason, let retryState):
break
}
}
let cancellable = AppDelegate.braze?.contentCards.subscribeToUpdates { [weak self] contentCards in
// Implement your completion handler to respond to updates in `contentCards`.
}
AsyncStream
// - Available in version 19.0.0+
Task {
for await event in AppDelegate.braze?.contentCards.eventsStream ?? AsyncStream { _ in } {
// Same switch statement as the cancellable example above.
}
}
let stream: AsyncStream<[Braze.ContentCard]> = AppDelegate.braze?.contentCards.cardsStream
Utilisez subscribeToEvents(_:) ou eventsStream à partir du SDK Swift 19.0.0. subscribeToUpdates(_:) et cardsStream sont le modèle précédent, obsolète depuis la version 19.0.0.
NSArray<BRZContentCardRaw *> *contentCards = AppDelegate.braze.contentCards.cards;
De plus, si vous souhaitez vous abonner aux événements Content Cards, vous pouvez appeler subscribeToEvents:. Chaque type d’événement est relié à sa propre classe (par exemple, BRZContentCardsDataUpdatedEvent), que vous pouvez distinguer avec isKindOfClass:. Le replay initial du cache et les mises à jour de données suivantes sont tous deux reliés à BRZContentCardsDataUpdatedEvent ; vérifiez reason par rapport à BRZContentCardsDataUpdatedEvent.cacheReplayReason pour les différencier :
// - Available in version 19.0.0+
// This subscription is maintained through a Braze cancellable, which will continue to observe for events until the subscription is cancelled.
BRZCancellable *cancellable = [self.braze.contentCards subscribeToEvents:^(BRZContentCardsEvent *event) {
if ([event isKindOfClass:[BRZContentCardsDataUpdatedEvent class]]) {
BRZContentCardsDataUpdatedEvent *updated = (BRZContentCardsDataUpdatedEvent *)event;
if (updated.reason == BRZContentCardsDataUpdatedEvent.cacheReplayReason) {
// Initial cache snapshot, delivered immediately after subscribing
} else {
// Cache changed after the initial replay
}
} else if ([event isKindOfClass:[BRZContentCardsCacheLoadEvent class]]) {
// Cache loaded at the start of a user session (for example, after `changeUser()`)
}
}];
BRZCancellable *cancellable = [self.braze.contentCards subscribeToUpdates:^(NSArray<BRZContentCardRaw *> *contentCards) {
// Implement your completion handler to respond to updates in `contentCards`.
}];
Utilisez subscribeToEvents: à partir du SDK Swift 19.0.0. subscribeToUpdates: est le modèle précédent, obsolète depuis la version 19.0.0.
Pour savoir quand chaque événement se déclenche et ce que signifient chaque raison de mise à jour, état de nouvelle tentative, action analytique et raison d’erreur, consultez Abonnements aux événements.
Étape 3 : Implémenter les analyses
Les impressions, clics et fermetures des Content Cards ne sont pas automatiquement enregistrés dans votre vue personnalisée. Vous devez implémenter chaque méthode respective pour enregistrer correctement tous les indicateurs dans les analyses du tableau de bord de Braze.
Étape 4 : Tester votre carte (facultatif)
Pour tester votre Content Card :
- Définissez un utilisateur actif dans votre application en appelant la méthode
changeUser(). - Dans Braze, accédez à Campaigns, puis créez une nouvelle campagne de Content Cards.
- Dans votre campagne, sélectionnez Test, puis saisissez le
user-idde l’utilisateur test. Lorsque vous êtes prêt, sélectionnez Send Test. Vous pourrez lancer une Content Card sur votre appareil peu après.

Emplacements des Content Cards
Les Content Cards peuvent être utilisées de nombreuses manières différentes. Trois implémentations courantes consistent à les utiliser comme centre de messages, comme bannière publicitaire dynamique ou comme carrousel d’images. Pour chacun de ces emplacements, vous attribuerez des paires clé-valeur (la propriété extras dans le modèle de données) à vos Content Cards et, en fonction des valeurs, ajusterez dynamiquement le comportement, l’apparence ou la fonctionnalité de la carte pendant l’exécution.

Boîte de réception de messages
Les Content Cards peuvent être utilisées pour simuler un centre de messages. Dans ce format, chaque message est sa propre carte qui contient des paires clé-valeur qui contrôlent les événements au clic. Ces paires clé-valeur sont les identifiants clés que l’application examine pour décider où rediriger l’utilisateur lorsqu’il clique sur un message de la boîte de réception. Les valeurs des paires clé-valeur sont arbitraires.
Exemple
Par exemple, vous pourriez vouloir créer deux cartes de message : un appel à l’action invitant les utilisateurs à activer les recommandations de lecture et un code de réduction destiné à votre Segment de nouveaux abonnés.
Des clés comme body, title et buttonText peuvent avoir des valeurs de chaîne simples que vos marketeurs peuvent définir. Des clés comme terms peuvent avoir des valeurs fournissant un petit ensemble de formulations approuvées par votre service juridique. Des clés comme style et class_type ont des valeurs de chaîne que vous pouvez définir pour déterminer comment votre carte s’affiche dans votre application ou sur votre site.
Paires clé-valeur pour la carte de recommandation de lecture :
| Clé | Valeur |
|---|---|
body |
Ajoutez vos centres d’intérêt à votre profil Politer Weekly pour des recommandations de lecture personnalisées. |
style |
info |
class_type |
notification_center |
card_priority |
1 |
Paires clé-valeur pour un coupon nouvel abonné :
| Clé | Valeur |
|---|---|
title |
Abonnez-vous pour des jeux illimités |
body |
Offre spéciale de fin d’été - Profitez de 10 % de réduction sur les jeux Politer |
buttonText |
S’abonner maintenant |
style |
promo |
class_type |
notification_center |
card_priority |
2 |
terms |
new_subscribers_only |
Informations supplémentaires pour Android
Dans le SDK Android et FireOS, la logique du centre de messages est pilotée par la valeur class_type fournie par les paires clé-valeur de Braze. En utilisant la méthode createContentCardable, vous pouvez filtrer et identifier ces types de classes.
Utilisation de class_type pour le comportement au clic
Lorsque nous chargeons les données des Content Cards dans nos classes personnalisées, nous utilisons la propriété ContentCardClass des données pour déterminer quelle sous-classe concrète doit être utilisée pour stocker les données.
private fun createContentCardable(metadata: Map<String, Any>, type: ContentCardClass?): ContentCardable?{
return when(type){
ContentCardClass.AD -> Ad(metadata)
ContentCardClass.MESSAGE_WEB_VIEW -> WebViewMessage(metadata)
ContentCardClass.NOTIFICATION_CENTER -> FullPageMessage(metadata)
ContentCardClass.ITEM_GROUP -> Group(metadata)
ContentCardClass.ITEM_TILE -> Tile(metadata)
ContentCardClass.COUPON -> Coupon(metadata)
else -> null
}
}
Ensuite, lors du traitement de l’interaction de l’utilisateur avec la liste de messages, nous pouvons utiliser le type du message pour déterminer quelle vue afficher à l’utilisateur.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//...
listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
when (val card = dataProvider[position]){
is WebViewMessage -> {
val intent = Intent(this, WebViewActivity::class.java)
val bundle = Bundle()
bundle.putString(WebViewActivity.INTENT_PAYLOAD, card.contentString)
intent.putExtras(bundle)
startActivity(intent)
}
is FullPageMessage -> {
val intent = Intent(this, FullPageContentCard::class.java)
val bundle = Bundle()
bundle.putString(FullPageContentCard.CONTENT_CARD_IMAGE, card.icon)
bundle.putString(FullPageContentCard.CONTENT_CARD_TITLE, card.messageTitle)
bundle.putString(FullPageContentCard.CONTENT_CARD_DESCRIPTION, card.cardDescription)
intent.putExtras(bundle)
startActivity(intent)
}
}
}
}
Utilisation de class_type pour le comportement au clic
Lorsque nous chargeons les données des Content Cards dans nos classes personnalisées, nous utilisons la propriété ContentCardClass des données pour déterminer quelle sous-classe concrète doit être utilisée pour stocker les données.
private ContentCardable createContentCardable(Map<String, ?> metadata, ContentCardClass type){
switch(type){
case ContentCardClass.AD:{
return new Ad(metadata);
}
case ContentCardClass.MESSAGE_WEB_VIEW:{
return new WebViewMessage(metadata);
}
case ContentCardClass.NOTIFICATION_CENTER:{
return new FullPageMessage(metadata);
}
case ContentCardClass.ITEM_GROUP:{
return new Group(metadata);
}
case ContentCardClass.ITEM_TILE:{
return new Tile(metadata);
}
case ContentCardClass.COUPON:{
return new Coupon(metadata);
}
default:{
return null;
}
}
}
Ensuite, lors du traitement de l’interaction de l’utilisateur avec la liste de messages, nous pouvons utiliser le type du message pour déterminer quelle vue afficher à l’utilisateur.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
//...
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
ContentCardable card = dataProvider.get(position);
if (card instanceof WebViewMessage){
Bundle intent = new Intent(this, WebViewActivity.class);
Bundle bundle = new Bundle();
bundle.putString(WebViewActivity.INTENT_PAYLOAD, card.getContentString());
intent.putExtras(bundle);
startActivity(intent);
}
else if (card instanceof FullPageMessage){
Intent intent = new Intent(this, FullPageContentCard.class);
Bundle bundle = Bundle();
bundle.putString(FullPageContentCard.CONTENT_CARD_IMAGE, card.getIcon());
bundle.putString(FullPageContentCard.CONTENT_CARD_TITLE, card.getMessageTitle());
bundle.putString(FullPageContentCard.CONTENT_CARD_DESCRIPTION, card.getCardDescription());
intent.putExtras(bundle)
startActivity(intent)
}
}
});
}
Carrousel
Vous pouvez configurer des Content Cards dans votre flux carrousel entièrement personnalisé, permettant aux utilisateurs de faire défiler et de visualiser des cartes mises en avant supplémentaires. Par défaut, les Content Cards sont triées par date de création (les plus récentes en premier), et vos utilisateurs voient toutes les cartes auxquelles ils sont éligibles.
Pour implémenter un carrousel de Content Cards :
- Créez une logique personnalisée qui observe les changements dans vos Content Cards et gère l’arrivée des Content Cards.
- Créez une logique personnalisée côté client pour afficher un nombre spécifique de cartes dans le carrousel à un moment donné. Par exemple, vous pourriez sélectionner les cinq premiers objets Content Card du tableau ou introduire des paires clé-valeur pour construire une logique conditionnelle.

Si vous implémentez un carrousel comme flux secondaire de Content Cards, assurez-vous de trier les cartes dans le bon flux à l’aide de paires clé-valeur.
Image uniquement
Les Content Cards n’ont pas besoin de ressembler à des « cartes ». Par exemple, les Content Cards peuvent apparaître sous la forme d’une image dynamique affichée de manière permanente sur votre page d’accueil ou en haut de pages désignées.
Pour obtenir ce résultat, vos marketeurs créeront une Campaign ou une étape du Canvas avec un type de Content Card Image Only. Ensuite, définissez des paires clé-valeur adaptées à l’utilisation des Content Cards comme contenu supplémentaire.