Saltar al contenido principal

Atributos de usuario personalizados

Los atributos de usuario son propiedades que describen a tus usuarios. Úsalos para personalizar mensajes, crear segmentos y analizar tu base de usuarios.

¿Qué son los atributos de usuario?​

Los atributos son pares clave-valor vinculados a perfiles de usuario:

{
"userId": "user_123",
"email": "[email protected]",
"attributes": {
"firstName": "John",
"lastName": "Doe",
"plan": "premium",
"signupDate": "2024-01-15",
"totalPurchases": 5,
"lastLoginDate": "2024-01-20",
"preferences": {
"newsletter": true,
"notifications": "email"
}
}
}

Configurar atributos​

Mediante SDK (lado cliente)​

import JoryioSDK from '@joryio/web-sdk';

const joryio = new JoryioSDK({ sdkKey: 'jry_sdk_web_...' });

// Identifica a un usuario
joryio.identify('user_123');

// Configura atributos por separado
joryio.setAttributes({
firstName: 'John',
lastName: 'Doe',
plan: 'premium',
signupDate: '2024-01-15'
});

// Actualiza los atributos más adelante
joryio.setAttributes({
plan: 'enterprise',
lastUpgrade: new Date().toISOString()
});

Mediante API (lado servidor)​

// Crea o actualiza un usuario con atributos
fetch('https://api-eu1.joryio.com/api/users/track', {
method: 'POST',
headers: {
'Authorization': 'Bearer jry_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
attributes: {
externalId: 'user_123',
attributes: {
firstName: 'John',
plan: 'premium',
totalOrders: 10,
lifetimeValue: 1250.00
}
}
})
});

Atributos estándar frente a personalizados​

Atributos estándar​

Envía los números de teléfono con + y el código de país

Envía siempre los números de teléfono en formato internacional completo (E.164): +, el código de país y luego el número - por ejemplo +972501234567. Un número sin + se lee con el país predeterminado para números de teléfono del espacio de trabajo; si no hay ninguno, o los dígitos se pueden leer de dos formas, se guarda sin verificar y no se usa para mensajes. Cómo se tratan los números de teléfono

Reservados por Joryio (se almacenan en el nivel raíz):

  • userId: identificador único de usuario.
  • email: dirección de email.
  • phone: número de teléfono.
  • externalId: ID de sistema externo.
  • createdAt: marca de tiempo de creación del usuario.
  • updatedAt: marca de tiempo de la última actualización.

Atributos personalizados​

Cualquier otra propiedad que definas (se almacena en el objeto attributes):

  • firstName, lastName, name
  • plan, subscription Tier
  • company, industry, jobTitle
  • totalPurchases, lifetimeValue
  • preferences, settings
  • Y cualquier otra cosa que necesites.

Tipos de datos​

Los atributos admiten varios tipos de datos:

Cadena​

{
firstName: "John",
plan: "premium",
country: "US"
}

Número​

{
age: 30,
totalPurchases: 15,
lifetimeValue: 1250.50
}

Booleano​

{
emailVerified: true,
newsletter: false,
isPremium: true
}

Fecha/marca de tiempo​

{
signupDate: "2024-01-15",
lastLoginDate: "2024-01-20T10:30:00Z",
trialEndsAt: "2024-02-15T23:59:59Z"
}
Usa el formato ISO 8601

Para las fechas, usa el formato ISO 8601: YYYY-MM-DDTHH:mm:ssZ.

Matriz​

{
tags: ["vip", "early-adopter"],
interests: ["technology", "sports", "music"],
purchasedProducts: ["product_1", "product_2"]
}

Objeto/anidado​

{
preferences: {
theme: "dark",
language: "en",
notifications: {
email: true,
sms: false,
push: true
}
},
address: {
street: "123 Main St",
city: "San Francisco",
state: "CA",
zip: "94102"
}
}

Cómo se decide un tipo​

Joryio nunca adivina por el NOMBRE de un campo. El tipo se resuelve en este orden:

  1. Declarado - alguien definió el tipo en la página Atributos (o en la página Eventos, para propiedades de evento). Esto siempre prevalece.
  2. Campo de comercio estándar - price, total, revenue, quantity, tax, shipping, discount, subtotal y value se tratan como números por defecto, envíes 12.34 o "12.34". Los identificadores como order_id y sku quedan fuera a propósito: suelen parecer numéricos, y tiparlos como números es la razón por la que un pedido 007 deja de coincidir.
  3. Inferido de tus datos - el tipo más común en una muestra, por evento. Product Added.step y Onboarding Step Tapped.step se tipan por separado.

Cuando los valores no coinciden​

Si más de un ~20% de los valores son de otro tipo, el atributo se muestra como Mixto con los recuentos (por ejemplo string 994 - number 448). Joryio no elige un lado: compara como texto - lo que nunca da una respuesta incorrecta, solo aproximada - y te pide que definas el tipo.

Definir el tipo corrige la comparación también para los valores ya almacenados: un campo declarado como número compara "12.34" y 12.34 como el mismo número, de modo que price > 100 deja de comparar texto (donde "90" > "100" es verdadero).

nota

Declarar un tipo cambia cómo se COMPARAN los valores. No reescribe lo almacenado: tus datos históricos conservan exactamente los valores que enviaste.

Qué cuesta definir un tipo​

Definir un tipo es una decisión sobre cómo tratar un desacuerdo, no una forma de terminarlo. Los valores que no se pueden leer como el tipo que elegiste dejan de coincidir con los filtros, y quedan fuera de ambos lados de un rango.

Supón que step tiene los números 1, 2, 3 en la mayoría de los eventos y las palabras "invite" y "photo" en unos pocos, y lo defines como Número:

filtroun contacto cuyo step es "invite"
step > 1no coincide
step <= 1no coincide
step = 1no coincide
step no es 1coincide
step existecoincide

Así que dos segmentos pensados para dividir tu audiencia en dos - step > 1 y step <= 1 - dejan a esos contactos en ninguno. Una prueba dividida construida así los pierde en silencio.

Los números escritos como texto no son problema: "12.34" se lee como 12.34 y coincide con normalidad. Solo se ven afectados los valores sin lectura posible como el tipo elegido.

La lista de atributos muestra cuántos valores se ven afectados junto al tipo, de modo que el desacuerdo sigue visible después de decidir. La corrección está en el origen - envía el valor en una forma consistente - porque nada aquí reescribe datos que ya enviaste.

Los campos estándar se tipan por ti​

Algunos campos tienen un significado que definimos nosotros, no tú, y su tipo es fijo:

  • Atributos de plataforma que escribe el sistema: lastEventTime (una fecha, aunque se almacene como texto), total_purchases, ml_churn_score, is_purchase_overdue.
  • Propiedades de comercio estándar: price, total, revenue, quantity, tax, shipping, discount, subtotal, value.

No necesitas definirlos y no puedes cambiarlos. Es deliberado: si el mismo campo estándar pudiera significar un número en un espacio de trabajo y texto en otro, nada construido encima - informes, recomendaciones, ingresos - podría confiar en él.

Si alguno de esos nombres significa otra cosa en tus datos, envíalo con un nombre distinto. Un price que en realidad es una etiqueta debería ser price_label. Todo lo que quede fuera de estas listas lo defines tú.

Ejemplos de atributos habituales​

E-commerce​

joryio.setAttributes({
// Información de la cuenta
accountType: "premium",
memberSince: "2024-01-15",

// Historial de compras
totalOrders: 15,
lastOrderDate: "2024-01-20",
lifetimeValue: 2500.00,
avgOrderValue: 166.67,

// Preferencias
favoriteCategory: "electronics",
preferredShipping: "express",

// Interacción
cartAbandoned: false,
wishlistItems: 5,
reviewsWritten: 3
});

SaaS​

joryio.setAttributes({
// Suscripción
plan: "pro",
billingCycle: "monthly",
subscriptionStatus: "active",
trialEndsAt: "2024-02-15T23:59:59Z",
mrr: 99,

// Uso
loginCount: 45,
lastLoginDate: "2024-01-20",
featuresUsed: ["export", "api", "integrations"],
apiCallsThisMonth: 10500,
storageUsedGB: 15.5,

// Equipo
teamSize: 8,
role: "admin",
companyName: "Acme Corp"
});

Medios y contenido​

joryio.setAttributes({
// Suscripción
subscriptionTier: "premium",
contentAccessLevel: "unlimited",

// Interacción
articlesRead: 125,
videosWatched: 45,
podcastsListened: 30,
favoriteTopics: ["technology", "business"],

// Comportamiento
avgSessionDuration: 25.5,
lastVisit: "2024-01-20T14:30:00Z",
deviceType: "mobile"
});

Actualizar atributos​

Combinar frente a reemplazar​

Combinar (predeterminado): actualiza los campos especificados.

// Atributos iniciales
{
firstName: "John",
plan: "free",
country: "US"
}

// Actualiza atributos (se combinan con los existentes)
joryio.setAttributes({
plan: "premium"
});

// Resultado (plan actualizado, se conservan los demás)
{
firstName: "John",
plan: "premium", // Updated
country: "US" // Preserved
}
Los atributos se combinan

Al llamar a setAttributes(), los atributos nuevos se combinan con los existentes. Los atributos existentes que no se mencionan en la llamada se conservan.

Incrementar/reducir​

Para los contadores, incrementa el valor en vez de obtener el valor actual:

// Incorrecto: puede producirse una condición de carrera
const current = await getUserAttribute('loginCount');
joryio.setAttributes({ loginCount: current + 1 });

// Correcto: incremento atómico
joryio.incrementAttribute('loginCount', 1);

// Reducir
joryio.incrementAttribute('creditsRemaining', -10);

Atributos de matriz​

Puedes almacenar y manipular matrices como valores de atributos:

// Configura un atributo de matriz
joryio.setAttributes({
tags: ['vip', 'early-adopter'],
interests: ['technology', 'sports']
});

// Add to array (only adds if value doesn't already exist)
joryio.addToArray('tags', 'premium');
// Resultado: ['vip', 'early-adopter', 'premium']

// Add duplicate (no-op, prevents duplicates)
joryio.addToArray('tags', 'vip');
// Resultado: ['vip', 'early-adopter', 'premium'] (sin cambios)

// Remove from array
joryio.removeFromArray('tags', 'early-adopter');
// Resultado: ['vip', 'premium']

Detalles de los métodos:

MétodoDescripción
addToArray(key, value)Añade el valor a la matriz si aún no existe (evita duplicados). Crea una matriz nueva si el atributo no existe.
removeFromArray(key, value)Elimina todas las instancias del valor de la matriz. Advierte si el atributo no es una matriz.
Casos de uso

Los atributos de matriz son ideales para:

  • Etiquetas de usuario: ['vip', 'trial', 'beta-tester'].
  • Intereses: ['sports', 'technology', 'fashion'].
  • Productos comprados: ['prod_123', 'prod_456'].
  • Feature flags: ['feature-a', 'feature-b'].
  • Roles: ['admin', 'editor'].

Usar atributos para segmentar​

Crea segmentos basados en atributos:

Filtro de atributo sencillo​

plan equals "premium"

Comparación numérica​

lifetimeValue >= 1000
totalPurchases > 5
age between 25 and 45

Filtros basados en fechas​

signupDate is within last 30 days
trialEndsAt is within next 7 days
lastLoginDate is more than 14 days ago

Coincidencia de cadenas​

email contains "@company.com"
country equals "US"
firstName exists
plan is not "free"

Filtros de matriz​

tags contains "vip"
interests contains any of ["technology", "business"]

Personalizar mensajes​

Usa atributos en el contenido de las campañas:

Personalización de email​

Hola, {{firstName}}:

Tu plan {{plan}} incluye estas ventajas:
...

{{#if trialEndsAt}}
Tu prueba termina el {{trialEndsAt}}. ¡Mejora ahora!
{{/if}}

Contenido dinámico​

{{#if plan == "free"}}
<p>¡Mejora a Premium para disfrutar de más funciones!</p>
{{else}}
<p>¡Gracias por ser miembro del plan {{plan}}!</p>
{{/if}}

Bloques condicionales​

{{#if totalPurchases > 10}}
<div class="vip-offer">
Como cliente valioso, aquí tienes una oferta exclusiva...
</div>
{{/if}}

Prácticas recomendadas para atributos​

1. Usa nombres descriptivos​

Correcto:

{
subscriptionTier: "premium",
lifetimeValueUSD: 1250.00,
emailVerified: true
}

Incorrecto:

{
sub: "p",
ltv: 1250,
verified: 1
}

2. Mantén la coherencia​

Usa la misma convención de nombres:

Correcto (camelCase):

{
firstName: "John",
lastName: "Doe",
signupDate: "2024-01-15"
}

Incorrecto (mezclado):

{
first_name: "John",
LastName: "Doe",
"signup-date": "2024-01-15"
}

3. Usa tipos adecuados​

Correcto:

{
age: 30, // Número
isPremium: true, // Booleano
signupDate: "2024-01-15", // Cadena de fecha ISO
tags: ["vip", "beta"] // Matriz
}

Incorrecto:

{
age: "30", // Cadena en vez de número
isPremium: "true", // Cadena en vez de booleano
signupDate: 1705276800, // Marca de tiempo en vez de ISO
tags: "vip,beta" // Cadena en vez de matriz
}

4. No almacenes datos sensibles​

No almacenes nunca:

  • Contraseñas ni hashes de contraseñas.
  • Números completos de tarjetas de crédito.
  • Números de seguridad social.
  • Datos bancarios.
  • Información de salud.

Es seguro almacenar:

  • Los últimos cuatro dígitos de la tarjeta.
  • El tipo de método de pago ("visa", "mastercard").
  • Tokens cifrados o con hash.
  • Información pública del perfil.

5. Mantén cortos los nombres de atributos​

Correcto: plan, ltv, mrr Incorrecto: currentSubscriptionPlanTierLevel

Nombres de atributos reservados​

Evita usar estos nombres reservados:

  • userId, user_id, id
  • email
  • phone
  • createdAt, created_at
  • updatedAt, updated_at
  • $app_id, $platform (con el prefijo $)

Actualizaciones masivas​

Actualiza atributos de varios usuarios:

// API: Bulk update - each field of POST /users/track accepts an array (attributes: max 1000)
POST /users/track
{
"attributes": [
{
"externalId": "user_1",
"attributes": { "plan": "premium" }
},
{
"externalId": "user_2",
"attributes": { "plan": "enterprise" }
}
]
}

Límites de atributos​

LímiteValor
Máximo de atributos por usuario200
Longitud máxima del nombre de atributo100 caracteres
Longitud máxima de valor de cadena10.000 caracteres
Longitud máxima de matriz100 elementos
Profundidad máxima de anidamiento5 niveles

Solución de problemas​

Los atributos no aparecen​

  1. Comprueba la ortografía del nombre del atributo.
  2. Verifica que el usuario se haya identificado.
  3. Activa el modo de depuración para ver las llamadas de API.
  4. Comprueba si hay errores de API en la respuesta.

El atributo no se actualiza​

  1. Asegúrate de usar la combinación, no el reemplazo.
  2. Comprueba que el tipo de datos coincida.
  3. Verifica que el nombre del atributo sea correcto.
  4. Comprueba los límites de velocidad.

La segmentación no funciona​

  1. Verifica que el atributo exista para los usuarios.
  2. Comprueba el tipo de datos del atributo.
  3. Prueba la lógica de filtro con usuarios conocidos.
  4. Asegúrate de que los valores de atributo coincidan exactamente con el filtro.

Próximos pasos​