Crear Content Cards
Este artículo describe el enfoque básico que utilizarás al implementar Content Cards personalizadas, así como tres casos de uso comunes. Asume que ya has leído los demás artículos de la guía de personalización de Content Cards para comprender qué se puede hacer de forma predeterminada y qué requiere código personalizado. Es especialmente útil comprender cómo registrar los análisis de tus Content Cards personalizadas.

¿Usas Content Cards para mensajes de tipo banner? Prueba los Banners— perfectos para mensajes en línea y persistentes dentro de la aplicación y la Web.
Creación de una tarjeta
Paso 1: Crear una interfaz personalizada
Primero, crea tu componente HTML personalizado que se utilizará para renderizar las tarjetas.
Primero, crea tu propio fragmento personalizado. El ContentCardsFragment predeterminado solo está diseñado para manejar nuestros tipos predeterminados de Content Cards, pero es un buen punto de partida.
Primero, crea tu propio componente de controlador de vista personalizado. El BrazeContentCardUI.ViewController predeterminado solo está diseñado para manejar nuestros tipos predeterminados de Content Cards, pero es un buen punto de partida.
Paso 2: Suscribirse a las actualizaciones de tarjetas
Registra una función de devolución de llamada para suscribirte a las actualizaciones de datos cuando se refresquen las tarjetas. Puedes analizar los objetos de Content Card y extraer los datos de su carga útil, como title, cardDescription e imageUrl, y luego usar los datos del modelo resultante para rellenar tu interfaz personalizada.
Para obtener los modelos de datos de Content Card, suscríbete a las actualizaciones de Content Cards. Presta especial atención a las siguientes propiedades:
id: Representa la cadena del ID de la Content Card. Es el identificador único utilizado para registrar análisis de Content Cards personalizadas.extras: Incluye todos los pares clave-valor del panel de Braze.
Todas las propiedades fuera de id y extras son opcionales para analizar Content Cards personalizadas. Para más información sobre el modelo de datos, consulta el artículo de integración de cada plataforma: Android, iOS, Web.
Usa subscribeToContentCardsEvents para recibir eventos de Content Cards. El SDK llama a tu controlador con un objeto de evento. Filtra por event.type para manejar cada tipo de evento. Para más información sobre los valores de evento, consulta Suscripciones a eventos.
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);

Las Content Cards solo se refrescan al iniciar la sesión si llamas a subscribeToContentCardsEvents() (o la obsoleta subscribeToContentCardsUpdates()) antes de openSession(). También puedes refrescar manualmente la fuente en cualquier momento.
Para saber cuándo se dispara cada evento y qué significan cada motivo de actualización, estado de reintento, acción de análisis y motivo de error, consulta Suscripciones a eventos.
Usa subscribeToContentCardsEvents en Web SDK 7.0.0 y versiones posteriores. subscribeToContentCardsUpdates es el patrón anterior, obsoleto a partir de la versión 7.0.0. El patrón anterior solo entrega las tarjetas actuales, por lo que no puede indicarte por qué cambiaron las tarjetas o cuándo falló un refresco.
Paso 2a: Crear una variable de suscriptor privada
Para suscribirte a las actualizaciones de tarjetas, primero declara una variable privada en tu clase personalizada para mantener tu suscriptor:
// - Available in version 44.0.0+
private IEventSubscriber<ContentCardsEvent> mContentCardsEventSubscriber;
private IEventSubscriber<ContentCardsUpdatedEvent> mContentCardsUpdatedSubscriber;
Paso 2b: Suscribirse a eventos
Añade el siguiente código para suscribirte con subscribeToContentCardsEvents(), normalmente dentro del Activity.onCreate() de tu actividad personalizada de Content Cards. Haz coincidencia de patrones con las subclases de ContentCardsEvent que necesites.
// - 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();
}
Los eventos llegan en un hilo en segundo plano. Cambia al hilo principal antes de actualizar las vistas.
Paso 2c: Cancelar la suscripción
Cancela la suscripción cuando tu actividad personalizada salga de la vista. Añade el siguiente código al método del ciclo de vida onDestroy() de tu actividad:
// - Available in version 44.0.0+
Braze.getInstance(context).removeSingleSubscription(mContentCardsEventSubscriber, ContentCardsEvent.class);
Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class);
Paso 2a: Crear una variable de suscriptor privada
Para suscribirte a los eventos de tarjetas, primero declara una variable privada en tu clase personalizada para mantener tu suscriptor:
// - Available in version 44.0.0+
private var contentCardsEventSubscriber: IEventSubscriber<ContentCardsEvent>? = null
private var contentCardsUpdatedSubscriber: IEventSubscriber<ContentCardsUpdatedEvent>? = null
Paso 2b: Suscribirse a eventos
Añade el siguiente código para suscribirte con subscribeToContentCardsEvents(), normalmente dentro del Activity.onCreate() de tu actividad personalizada de Content Cards. Haz coincidencia de patrones con las subclases de ContentCardsEvent que necesites.
// - 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
}
Los eventos llegan en un hilo en segundo plano. Cambia al hilo principal antes de actualizar las vistas.
Paso 2c: Cancelar la suscripción
Cancela la suscripción cuando tu actividad personalizada salga de la vista. Añade el siguiente código al método del ciclo de vida onDestroy() de tu actividad:
// - Available in version 44.0.0+
Braze.getInstance(context).removeSingleSubscription(contentCardsEventSubscriber, ContentCardsEvent::class.java)
Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java)
Para saber cuándo se dispara cada evento y qué significan cada motivo de actualización, estado de reintento, acción de análisis y motivo de error, consulta Suscripciones a eventos.
Usa subscribeToContentCardsEvents en Android SDK 44.0.0 y versiones posteriores. subscribeToContentCardsUpdates es el patrón anterior, obsoleto a partir de la versión 44.0.0.
Para acceder al modelo de datos de Content Cards, llama a contentCards.cards en tu instancia de braze.
let cards: [Braze.ContentCard] = AppDelegate.braze?.contentCards.cards
Además, puedes suscribirte a los eventos de Content Cards para observar cambios de caché, análisis y errores. Puedes hacerlo de dos maneras:
- Manteniendo un cancelable; o
- Manteniendo un
AsyncStream.
Cancelable
// - 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
Usa subscribeToEvents(_:) o eventsStream en Swift SDK 19.0.0 y versiones posteriores. subscribeToUpdates(_:) y cardsStream son el patrón anterior, obsoleto a partir de la versión 19.0.0.
NSArray<BRZContentCardRaw *> *contentCards = AppDelegate.braze.contentCards.cards;
Además, si deseas suscribirte a los eventos de Content Cards, puedes llamar a subscribeToEvents:. Cada tipo de evento se conecta a su propia clase (por ejemplo, BRZContentCardsDataUpdatedEvent), que puedes discriminar con isKindOfClass:. La reproducción inicial de la caché y las actualizaciones de datos posteriores se conectan a BRZContentCardsDataUpdatedEvent; comprueba reason contra BRZContentCardsDataUpdatedEvent.cacheReplayReason para distinguirlas:
// - 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`.
}];
Usa subscribeToEvents: en Swift SDK 19.0.0 y versiones posteriores. subscribeToUpdates: es el patrón anterior, obsoleto a partir de la versión 19.0.0.
Para saber cuándo se dispara cada evento y qué significan cada motivo de actualización, estado de reintento, acción de análisis y motivo de error, consulta Suscripciones a eventos.
Paso 3: Implementar análisis
Las impresiones, clics y descartes de Content Cards no se registran automáticamente en tu vista personalizada. Debes implementar cada método respectivo para registrar correctamente todas las métricas en los análisis del panel de Braze.
Paso 4: Probar tu tarjeta (opcional)
Para probar tu Content Card:
- Establece un usuario activo en tu aplicación llamando al método
changeUser(). - En Braze, ve a Campaigns y luego crea una nueva campaña de Content Card.
- En tu campaña, selecciona Test e introduce el
user-iddel usuario de prueba. Cuando estés listo, selecciona Send Test. Podrás lanzar una Content Card en tu dispositivo en breve.

Ubicaciones de Content Cards
Las Content Cards pueden utilizarse de muchas formas diferentes. Tres implementaciones comunes son usarlas como centro de mensajes, como anuncio de imagen dinámica o como carrusel de imágenes. Para cada una de estas ubicaciones, asignarás pares clave-valor (la propiedad extras en el modelo de datos) a tus Content Cards, y según los valores, ajustarás dinámicamente el comportamiento, la apariencia o la funcionalidad de la tarjeta durante el tiempo de ejecución.

Buzón de mensajes
Las Content Cards pueden utilizarse para simular un centro de mensajes. En este formato, cada mensaje es su propia tarjeta que contiene pares clave-valor que controlan los eventos al hacer clic. Estos pares clave-valor son los identificadores clave que la aplicación examina cuando decide a dónde dirigirse cuando el usuario hace clic en un mensaje del buzón de entrada. Los valores de los pares clave-valor son arbitrarios.
Ejemplo
Por ejemplo, puede que quieras crear dos tarjetas de mensaje: una llamada a la acción para que los usuarios habiliten las recomendaciones de lectura y un código de cupón para tu nuevo Segment de suscriptores.
Las claves como body, title y buttonText pueden tener valores de cadena simples que tus especialistas en marketing pueden configurar. Las claves como terms pueden tener valores que proporcionan una pequeña colección de frases aprobadas por tu departamento legal. Las claves como style y class_type tienen valores de cadena que puedes configurar para determinar cómo se renderiza tu tarjeta en tu aplicación o sitio.
Pares clave-valor para la tarjeta de recomendaciones de lectura:
| Clave | Valor |
|---|---|
body |
Add your interests to your Politer Weekly profile for personal reading recommendations. |
style |
info |
class_type |
notification_center |
card_priority |
1 |
Pares clave-valor para un cupón de nuevo suscriptor:
| Clave | Valor |
|---|---|
title |
Subscribe for unlimited games |
body |
End of Summer Special - Enjoy 10% off Politer games |
buttonText |
Subscribe Now |
style |
promo |
class_type |
notification_center |
card_priority |
2 |
terms |
new_subscribers_only |
Información adicional para Android
En el SDK de Android y FireOS, la lógica del centro de mensajes se basa en el valor class_type que proporcionan los pares clave-valor de Braze. Usando el método createContentCardable, puedes filtrar e identificar estos tipos de clase.
Uso de class_type para el comportamiento al hacer clic
Cuando inflamos los datos de Content Card en nuestras clases personalizadas, usamos la propiedad ContentCardClass de los datos para determinar qué subclase concreta debe usarse para almacenar los datos.
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
}
}
Luego, al gestionar la interacción del usuario con la lista de mensajes, podemos usar el tipo de mensaje para determinar qué vista mostrar al usuario.
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)
}
}
}
}
Uso de class_type para el comportamiento al hacer clic
Cuando inflamos los datos de Content Card en nuestras clases personalizadas, usamos la propiedad ContentCardClass de los datos para determinar qué subclase concreta debe usarse para almacenar los datos.
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;
}
}
}
Luego, al gestionar la interacción del usuario con la lista de mensajes, podemos usar el tipo de mensaje para determinar qué vista mostrar al usuario.
@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)
}
}
});
}
Carrusel
Puedes configurar Content Cards en tu fuente de carrusel totalmente personalizada, lo que permite a los usuarios deslizar y ver tarjetas destacadas adicionales. De forma predeterminada, las Content Cards se ordenan por fecha de creación (las más recientes primero) y tus usuarios verán todas las tarjetas para las que sean elegibles.
Para implementar un carrusel de Content Cards:
- Crea una lógica personalizada que observe los cambios en tus Content Cards y gestione la llegada de Content Cards.
- Crea una lógica personalizada del lado del cliente para mostrar un número específico de tarjetas en el carrusel en un momento dado. Por ejemplo, podrías seleccionar los primeros cinco objetos de Content Card del arreglo o introducir pares clave-valor para construir lógica condicional.

Si estás implementando un carrusel como una fuente secundaria de Content Cards, asegúrate de ordenar las tarjetas en la fuente correcta usando pares clave-valor.
Solo imagen
Las Content Cards no tienen que verse como “tarjetas”. Por ejemplo, las Content Cards pueden aparecer como una imagen dinámica que se muestra de forma persistente en tu página de inicio o en la parte superior de páginas designadas.
Para lograr esto, tus especialistas en marketing crearán una Campaign o un paso en Canvas con un tipo de Content Card Solo imagen. Luego, configura pares clave-valor que sean apropiados para usar Content Cards como contenido suplementario.