Ir al contenido

Análisis push y registro de eventos personalizados

Esta página cubre los siguientes flujos de trabajo: análisis nativos de push (aperturas, Influenced Opens e informes de Campaign) y registro de datos personalizados (eventos personalizados y atributos) a partir de cargas útiles push. Usa esta guía para identificar qué flujo de trabajo se aplica a tu caso de uso y sigue los pasos para tu plataforma.

Requisitos previos

Antes de empezar, completa la integración inicial de notificaciones push para tu plataforma:

Análisis nativos de push frente a registro de eventos personalizados

Los siguientes flujos de trabajo tienen distintas superficies de informes.

Categoría de análisis Descripción Dónde aparece
Análisis nativos de push Métricas de push como aperturas e Influenced Opens, vinculadas a Campaigns de push en Braze Análisis de Campaigns de push, eventos de participación en mensajes de Currents, generador de informes
Eventos y atributos personalizados Análisis que defines y registras a través de métodos del SDK o del endpoint /users/track Perfiles de usuario, segmentación, Campaigns y Canvas basados en acciones, análisis de eventos personalizados

Lo que Braze registra automáticamente

Cuando tu integración de SDK está configurada, Braze registra automáticamente los datos principales de interacción del canal, incluyendo aperturas push e Influenced Opens. No se requiere código adicional para el análisis estándar de push. Para consultar una lista completa de los datos recopilados automáticamente, consulta Recopilación de datos del SDK.

Para más detalles, consulta lo siguiente:

Conservar los análisis push nativos con el manejo push personalizado

Es posible que utilices un controlador push personalizado cuando necesites integrar varios proveedores push, procesar datos de carga útil adicionales o implementar una lógica de visualización de notificaciones personalizada. Si utilizas un controlador push personalizado, debes seguir pasando las cargas útiles push a los métodos del SDK de Braze. Esto permite a Braze extraer los datos de seguimiento integrados y registrar los análisis push nativos (aperturas, Influenced Opens y métricas de entrega).

Si tienes un FirebaseMessagingService personalizado, llama a BrazeFirebaseMessagingService.handleBrazeRemoteMessage(...) dentro de tu método onMessageReceived. Ten en cuenta que tu subclase de FirebaseMessagingService debe terminar la ejecución en 9 segundos desde la invocación para evitar ser marcada o terminada por el sistema Android.

public class MyFirebaseMessagingService extends FirebaseMessagingService {
  @Override
  public void onMessageReceived(RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);
    if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) {
      // Braze processed a Braze push payload.
    } else {
      // Non-Braze payload: pass to your other handlers.
    }
  }
}

Para ver un ejemplo de implementación completo, consulta la aplicación de ejemplo de push Firebase del SDK de Braze para Android.

En una integración push manual, reenvía las devoluciones de llamada de notificaciones en segundo plano y de notificaciones de usuario a Braze.

Notificaciones en segundo plano:

if let braze = AppDelegate.braze, braze.notifications.handleBackgroundNotification(
  userInfo: userInfo,
  fetchCompletionHandler: completionHandler
) {
  return
}
completionHandler(.noData)

Respuestas a notificaciones de usuario:

if let braze = AppDelegate.braze, braze.notifications.handleUserNotification(
  response: response,
  withCompletionHandler: completionHandler
) {
  return
}
completionHandler()

Notificaciones en primer plano:

func userNotificationCenter(
  _ center: UNUserNotificationCenter,
  willPresent notification: UNNotification,
  withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
  if let braze = AppDelegate.braze {
    braze.notifications.handleForegroundNotification(notification: notification)
  }
  if #available(iOS 14.0, *) {
    completionHandler([.banner, .list, .sound])
  } else {
    completionHandler([.alert, .sound])
  }
}

Para ver un ejemplo de implementación completo, consulta el ejemplo de push manual del SDK Swift de Braze (AppDelegate.swift).

Para notificaciones push web, configura tu prestador de servicios y la inicialización del SDK como se describe en Notificaciones push web.

Para más ejemplos de código, consulta el repositorio del SDK Web de Braze.

Registro de datos personalizados desde cargas útiles push

Utiliza esta sección cuando necesites registrar datos adicionales de los pares clave-valor de la carga útil push, como eventos personalizados o atributos vinculados a tu lógica de negocio.

Para más información sobre eventos personalizados, consulta Eventos personalizados. Para registrar eventos personalizados a través de métodos del SDK, consulta Registro de eventos personalizados.

Opción A: Registrar con el endpoint /users/track

Puedes registrar análisis en tiempo real llamando al endpoint /users/track.

Para identificar el perfil de usuario, incluye braze_id en los pares clave-valor de tu carga útil push.

Opción B: Registrar con métodos del SDK después del lanzamiento de la aplicación

También puedes guardar los datos de la carga útil de forma local y registrar eventos personalizados y atributos a través de métodos del SDK después de que la aplicación se inicialice. Este enfoque es común en flujos de extensión de contenido de notificaciones, donde los datos de análisis se persisten primero y se envían en el siguiente lanzamiento de la aplicación.

Registro desde una extensión de contenido de notificación (Swift)

Los siguientes pasos explican cómo guardar y enviar eventos personalizados, atributos personalizados y atributos de usuario desde una extensión de contenido de notificación en Swift.

Paso 1: Configura los grupos de aplicaciones en Xcode

En Xcode, añade la capacidad App Groups al destino de tu aplicación principal. Activa App Groups y haz clic en + para añadir un nuevo grupo. Utiliza el identificador de paquete de tu aplicación para crear el identificador de grupo (por ejemplo, group.com.company.appname.xyz). Activa App Groups tanto para el destino de tu aplicación principal como para el destino de la extensión de contenido.

Xcode mostrando la capacidad App Groups habilitada para la aplicación principal y la extensión de notificación

Paso 2: Elige qué registrar

Antes de implementar los fragmentos de código, elige qué categoría de análisis quieres registrar:

  • Eventos personalizados: acciones que los usuarios realizan (por ejemplo, completar un flujo o tocar un elemento específico de la interfaz). Utiliza eventos personalizados para desencadenantes basados en acciones, segmentación y análisis de eventos. Para más información, consulta Eventos personalizados y Registro de eventos personalizados.
  • Atributos personalizados: campos del perfil que tú defines (por ejemplo, plan_tier o preferred_language) y actualizas con el tiempo. Para más información, consulta Atributos personalizados y Configuración de atributos de usuario.
  • Atributos de usuario: campos estándar del perfil (por ejemplo, correo electrónico, nombre y número de teléfono). En el código de ejemplo, estos se representan mediante un modelo tipado UserAttribute y luego se asignan a los campos de usuario de Braze.

Los archivos auxiliares en esta sección (RemoteStorage, UserAttribute y EventName Dictionary) son archivos de utilidad locales que esta implementación de ejemplo utiliza. No son clases integradas del SDK. Almacenan datos derivados de la carga útil en UserDefaults, definen un modelo tipado para actualizaciones de usuario pendientes y estandarizan la construcción de cargas útiles de eventos. Para más información sobre el comportamiento del almacenamiento local de datos, consulta Almacenamiento.

Guardar eventos personalizados

Crea la carga útil de análisis construyendo un diccionario, rellenando los metadatos y guardándola con el archivo auxiliar.

  1. Inicializa un diccionario con los metadatos del evento.
  2. Inicializa userDefaults para recuperar y almacenar los datos del evento.
  3. Si se encuentra un array existente, añade y guarda.
  4. Si no existe ningún array, guarda uno nuevo.
func saveCustomEvent(with properties: [String: Any]? = nil) {
  // 1
  let customEventDictionary = Dictionary(eventName: "YOUR-EVENT-NAME", properties: properties)

  // 2
  let remoteStorage = RemoteStorage(storageType: .suite)

  // 3
  if var pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] {
    pendingEvents.append(contentsOf: [customEventDictionary])
    remoteStorage.store(pendingEvents, forKey: .pendingCustomEvents)
  } else {
    // 4
    remoteStorage.store([customEventDictionary], forKey: .pendingCustomEvents)
  }
}
- (void)saveCustomEvent:(NSDictionary<NSString *, id> *)properties {
  // 1
  NSDictionary<NSString *, id> *customEventDictionary = [[NSDictionary alloc] initWithEventName:@"YOUR-EVENT-NAME" properties:properties];

  // 2
  RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
  NSMutableArray *pendingEvents = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents] mutableCopy];

  // 3
  if (pendingEvents) {
    [pendingEvents addObject:customEventDictionary];
    [remoteStorage store:pendingEvents forKey:RemoteStorageKeyPendingCustomEvents];
  } else {
    // 4
    [remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomEvents];
  }
}

Enviar eventos personalizados a Braze

Registra los análisis guardados justo después de la inicialización del SDK.

  1. Itera sobre los eventos pendientes.
  2. Itera sobre los pares clave-valor de cada evento.
  3. Busca la clave event_name.
  4. Añade los pares clave-valor restantes al diccionario properties.
  5. Registra cada evento personalizado.
  6. Elimina los eventos pendientes del almacenamiento.
func logPendingCustomEventsIfNecessary() {
  let remoteStorage = RemoteStorage(storageType: .suite)
  guard let pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] else { return }

  // 1
  for event in pendingEvents {
    var eventName: String?
    var properties: [AnyHashable: Any] = [:]

    // 2
    for (key, value) in event {
      if key == "event_name" {
        // 3
        if let eventNameValue = value as? String {
          eventName = eventNameValue
        } else {
          print("Invalid type for event_name key")
        }
      } else {
        // 4
        properties[key] = value
      }
    }
    // 5
    if let eventName = eventName {
      AppDelegate.braze?.logCustomEvent(name: eventName, properties: properties)
    }
  }

  // 6
  remoteStorage.removeObject(forKey: .pendingCustomEvents)
}
- (void)logPendingEventsIfNecessary {
  RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
  NSArray *pendingEvents = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents];

  // 1
  for (NSDictionary<NSString *, id> *event in pendingEvents) {
    NSString *eventName = nil;
    NSMutableDictionary *properties = [NSMutableDictionary dictionary];

    // 2
    for (NSString* key in event) {
      if ([key isEqualToString:@"event_name"]) {
        // 3
        if ([[event objectForKey:key] isKindOfClass:[NSString class]]) {
          eventName = [event objectForKey:key];
        } else {
          NSLog(@"Invalid type for event_name key");
        }
      } else {
        // 4
        properties[key] = event[key];
      }
    }
    // 5
    if (eventName != nil) {
      [AppDelegate.braze logCustomEvent:eventName properties:properties];
    }
  }

  // 6
  [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomEvents];
}

Guardar atributos personalizados

Crea el diccionario de análisis como un nuevo diseño y luego persístelo.

  1. Inicializa un diccionario con los metadatos del atributo.
  2. Inicializa userDefaults para recuperar y almacenar los datos del atributo.
  3. Si se encuentra un array existente, añade y guarda.
  4. Si no existe ningún array, guarda uno nuevo.
func saveCustomAttribute() {
  // 1
  let customAttributeDictionary: [String: Any] = ["YOUR-CUSTOM-ATTRIBUTE-KEY": "YOUR-CUSTOM-ATTRIBUTE-VALUE"]

  // 2
  let remoteStorage = RemoteStorage(storageType: .suite)

  // 3
  if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] {
    pendingAttributes.append(contentsOf: [customAttributeDictionary])
    remoteStorage.store(pendingAttributes, forKey: .pendingCustomAttributes)
  } else {
    // 4
    remoteStorage.store([customAttributeDictionary], forKey: .pendingCustomAttributes)
  }
}
- (void)saveCustomAttribute {
  // 1
  NSDictionary<NSString *, id> *customAttributeDictionary = @{ @"YOUR-CUSTOM-ATTRIBUTE-KEY": @"YOUR-CUSTOM-ATTRIBUTE-VALUE" };

  // 2
  RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
  NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes] mutableCopy];

  // 3
  if (pendingAttributes) {
    [pendingAttributes addObject:customAttributeDictionary];
    [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingCustomAttributes];
  } else {
    // 4
    [remoteStorage store:@[ customAttributeDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes];
  }
}

Enviar atributos personalizados a Braze

Registra los análisis guardados justo después de la inicialización del SDK.

  1. Itera sobre los atributos pendientes.
  2. Itera sobre cada par clave-valor.
  3. Registra cada clave y valor de atributo personalizado.
  4. Elimina los atributos pendientes del almacenamiento.
func logPendingCustomAttributesIfNecessary() {
  let remoteStorage = RemoteStorage(storageType: .suite)
  guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] else { return }

  // 1
  pendingAttributes.forEach { setCustomAttributesWith(keysAndValues: $0) }

  // 4
  remoteStorage.removeObject(forKey: .pendingCustomAttributes)
}

func setCustomAttributesWith(keysAndValues: [String: Any]) {
  // 2
  for (key, value) in keysAndValues {
    // 3
    if let value = value as? [String] {
      setCustomAttributeArrayWithKey(key, andValue: value)
    } else {
      setCustomAttributeWithKey(key, andValue: value)
    }
  }
}
- (void)logPendingCustomAttributesIfNecessary {
  RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
  NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes];

  // 1
  for (NSDictionary<NSString*, id> *attribute in pendingAttributes) {
    [self setCustomAttributeWith:attribute];
  }

  // 4
  [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomAttributes];
}

- (void)setCustomAttributeWith:(NSDictionary<NSString *, id> *)keysAndValues {
  // 2
  for (NSString *key in keysAndValues) {
    // 3
    [self setCustomAttributeWith:key andValue:[keysAndValues objectForKey:key]];
  }
}

Guardar atributos de usuario

Al guardar atributos de usuario, crea un objeto personalizado para capturar qué campo de usuario se está actualizando (email, first_name, phone_number, etc.). El objeto debe ser compatible con el almacenamiento y la recuperación a través de UserDefaults. Consulta el archivo auxiliar UserAttribute en la pestaña Archivos auxiliares para ver un ejemplo.

  1. Inicializa un objeto UserAttribute codificado con el tipo correspondiente.
  2. Inicializa userDefaults para recuperar y almacenar los datos.
  3. Si se encuentra un array existente, añade y guarda.
  4. Si no existe ningún array, guarda uno nuevo.
func saveUserAttribute() {
  // 1
  guard let data = try? PropertyListEncoder().encode(UserAttribute.email("USER-ATTRIBUTE-VALUE")) else { return }

  // 2
  let remoteStorage = RemoteStorage(storageType: .suite)

  // 3
  if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] {
    pendingAttributes.append(contentsOf: [data])
    remoteStorage.store(pendingAttributes, forKey: .pendingUserAttributes)
  } else {
    // 4
    remoteStorage.store([data], forKey: .pendingUserAttributes)
  }
}
- (void)saveUserAttribute {
  // 1
  UserAttribute *userAttribute = [[UserAttribute alloc] initWithUserField:@"USER-ATTRIBUTE-VALUE" attributeType:UserAttributeTypeEmail];

  NSError *error;
  NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userAttribute requiringSecureCoding:YES error:&error];

  if (error != nil) {
    // log error
  }
  // 2
  RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
  NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes] mutableCopy];

  // 3
  if (pendingAttributes) {
    [pendingAttributes addObject:data];
    [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingUserAttributes];
  } else {
    // 4
    [remoteStorage store:@[data] forKey:RemoteStorageKeyPendingUserAttributes];
  }
}

Enviar atributos de usuario a Braze

Registra los análisis guardados justo después de la inicialización del SDK.

  1. Itera sobre los datos de pendingAttributes.
  2. Decodifica cada UserAttribute.
  3. Establece los campos de usuario según el tipo de atributo.
  4. Elimina los atributos de usuario pendientes del almacenamiento.
func logPendingUserAttributesIfNecessary() {
  let remoteStorage = RemoteStorage(storageType: .suite)
  guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] else { return }

  // 1
  for attributeData in pendingAttributes {
    // 2
    guard let userAttribute = try? PropertyListDecoder().decode(UserAttribute.self, from: attributeData) else { continue }

    // 3
    switch userAttribute {
    case .email(let email):
      AppDelegate.braze?.user.set(email: email)
    }
  }
  // 4
  remoteStorage.removeObject(forKey: .pendingUserAttributes)
}
- (void)logPendingUserAttributesIfNecessary {
  RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
  NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes];

  // 1
  for (NSData *attributeData in pendingAttributes) {
    NSError *error;

    // 2
    UserAttribute *userAttribute = [NSKeyedUnarchiver unarchivedObjectOfClass:[UserAttribute class] fromData:attributeData error:&error];

    if (error != nil) {
      // log error
    }

    // 3
    if (userAttribute) {
      switch (userAttribute.attributeType) {
        case UserAttributeTypeEmail:
          [self user].email = userAttribute.userField;
          break;
      }
    }
  }
  // 4
  [remoteStorage removeObjectForKey:RemoteStorageKeyPendingUserAttributes];
}

Archivo auxiliar RemoteStorage

enum RemoteStorageKey: String, CaseIterable {

  // MARK: - Notification Content Extension Analytics
  case pendingCustomEvents = "pending_custom_events"
  case pendingCustomAttributes = "pending_custom_attributes"
  case pendingUserAttributes = "pending_user_attributes"
}

enum RemoteStorageType {
  case standard
  case suite
}

class RemoteStorage: NSObject {
  private var storageType: RemoteStorageType = .standard
  private lazy var defaults: UserDefaults = {
    switch storageType {
    case .standard:
      return .standard
    case .suite:
      // Use the App Group identifier you created in Step 1.
      return UserDefaults(suiteName: "group.com.company.appname.xyz")!
    }
  }()

  init(storageType: RemoteStorageType = .standard) {
    self.storageType = storageType
  }

  func store(_ value: Any, forKey key: RemoteStorageKey) {
    defaults.set(value, forKey: key.rawValue)
  }

  func retrieve(forKey key: RemoteStorageKey) -> Any? {
    return defaults.object(forKey: key.rawValue)
  }

  func removeObject(forKey key: RemoteStorageKey) {
    defaults.removeObject(forKey: key.rawValue)
  }

  func resetStorageKeys() {
    for key in RemoteStorageKey.allCases {
      defaults.removeObject(forKey: key.rawValue)
    }
  }
}
@interface RemoteStorage ()

@property (nonatomic) StorageType storageType;
@property (nonatomic, strong) NSUserDefaults *defaults;

@end

@implementation RemoteStorage

- (id)initWithStorageType:(StorageType)storageType {
  if (self = [super init]) {
    self.storageType = storageType;
  }
  return self;
}

- (void)store:(id)value forKey:(RemoteStorageKey)key {
  [[self defaults] setValue:value forKey:[self rawValueForKey:key]];
}

- (id)retrieveForKey:(RemoteStorageKey)key {
  return [[self defaults] objectForKey:[self rawValueForKey:key]];
}

- (void)removeObjectForKey:(RemoteStorageKey)key {
  [[self defaults] removeObjectForKey:[self rawValueForKey:key]];
}

- (void)resetStorageKeys {
  [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomEvents]];
  [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomAttributes]];
  [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingUserAttributes]];
}

- (NSUserDefaults *)defaults {
  if (!_defaults) {
    switch (self.storageType) {
      case StorageTypeStandard:
        _defaults = [NSUserDefaults standardUserDefaults];
        break;
      case StorageTypeSuite:
        _defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.appname.xyz"];
        break;
    }
  }
  return _defaults;
}

- (NSString*)rawValueForKey:(RemoteStorageKey)remoteStorageKey {
    switch(remoteStorageKey) {
    case RemoteStorageKeyPendingCustomEvents:
      return @"pending_custom_events";
    case RemoteStorageKeyPendingCustomAttributes:
      return @"pending_custom_attributes";
    case RemoteStorageKeyPendingUserAttributes:
      return @"pending_user_attributes";
    default:
      [NSException raise:NSGenericException format:@"Unexpected FormatType."];
  }
}

Archivo auxiliar UserAttribute

enum UserAttribute: Hashable {
  case email(String?)
}

// MARK: - Codable
extension UserAttribute: Codable {
  private enum CodingKeys: String, CodingKey {
    case email
  }

  func encode(to encoder: Encoder) throws {
    var values = encoder.container(keyedBy: CodingKeys.self)

    switch self {
    case .email(let email):
      try values.encodeIfPresent(email, forKey: .email)
    }
  }

  init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)

    let email = try values.decodeIfPresent(String.self, forKey: .email)
    self = .email(email)
  }
}
@implementation UserAttribute

- (id)initWithUserField:(NSString *)userField attributeType:(UserAttributeType)attributeType {
  if (self = [super init]) {
    self.userField = userField;
    self.attributeType = attributeType;
  }
  return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder {
  [encoder encodeObject:self.userField forKey:@"userField"];
  [encoder encodeInteger:self.attributeType forKey:@"attributeType"];
}

- (id)initWithCoder:(NSCoder *)decoder {
  if (self = [super init]) {
    self.userField = [decoder decodeObjectForKey:@"userField"];

    NSInteger attributeRawValue = [decoder decodeIntegerForKey:@"attributeType"];
    self.attributeType = (UserAttributeType) attributeRawValue;
  }
  return self;
}

@end

Archivo auxiliar del diccionario EventName

extension Dictionary where Key == String, Value == Any {
  init(eventName: String, properties: [String: Any]? = nil) {
    self.init()
    self[PushNotificationKey.eventName.rawValue] = eventName

    if let properties = properties {
      for (key, value) in properties {
        self[key] = value
      }
    }
  }
}
@implementation NSMutableDictionary (Helper)

+ (instancetype)dictionaryWithEventName:(NSString *)eventName
                              properties:(NSDictionary *)properties {
  NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  dict[@"event_name"] = eventName;

  if (properties) {
    for (id key in properties) {
      dict[key] = properties[key];
    }
  }

  return dict;
}

@end

Análisis de resultados

Utiliza la superficie de informes que coincida con la categoría de análisis:

Categoría de análisis Dónde verlo en Braze
Análisis nativos de push Para ver las métricas de apertura de push a nivel de Campaign, navega a la página Campaign Analytics de tu Campaign de push. Para las definiciones de las métricas, consulta Influenced Opens. Para crear vistas de análisis personalizadas, navega a Analytics > Report Builder (New). Para los pasos de navegación, consulta Generador de informes. Para los esquemas de eventos a nivel de almacén de datos, consulta Eventos de participación en mensajes.
Eventos y atributos personalizados Para ver las tendencias de eventos personalizados, navega a Analytics > Custom Events Report. Para más detalles, consulta Eventos personalizados. Para inspeccionar valores a nivel de usuario, navega a la página Search Users y abre un perfil. Para los pasos, consulta Perfiles de usuario. Para filtrar audiencias por estos valores, navega a Audience > Segments. Para los pasos de navegación, consulta Crear un Segment y las opciones de filtro en Filtros de segmentación.

Para la creación de informes personalizados, consulta Generador de informes.

New Stuff!