Una herramienta de paneles de control con APIs de pájaros

Correo electrónico

·

24 mar 2022

Una herramienta de paneles de control con APIs de pájaros

Puntos clave

    • Las APIs de Bird se pueden combinar con Python and Plotly Dash para construir dashboards interactivos y potentes sin necesidad de la interfaz completa de Bird.

    • El proyecto demuestra cómo visualizar métricas y eventos utilizando las APIs de Métricas y Eventos de Bird dentro de una aplicación web personalizada.

    • Plotly Dash proporciona un marco de código abierto rápido para construir elementos de interfaz de usuario como menús desplegables, gráficos y tablas.

    • Los desarrolladores pueden extender la herramienta con analíticas de entregabilidad, filtrado y paginación para dashboards más completos.

    • Las mejoras futuras incluyen almacenamiento en caché, una mejorada interfaz de usuario e integración con otros productos de Bird o APIs de terceros.

    • La base de código (disponible en GitHub) ofrece un inicio sólido para cualquiera que desee construir dashboards alimentados por Bird o portales orientados al cliente.

Destacados de Q&A

  • ¿Cuál es el objetivo de este proyecto de dashboarding?

    Demuestra cómo los desarrolladores pueden usar las API de Bird con Python y Plotly Dash para crear paneles de control basados en datos que visualizan métricas de campaña y eventos recientes.

  • ¿Por qué usar Plotly Dash para Bird APIs?

    Dash es de código abierto, fácil de personalizar, e ideal para crear interfaces de usuario interactivas sin requerir experiencia en front-end.

  • ¿Qué muestra el dashboard?

    Visualiza métricas de series temporales desde la API de Métricas de Bird y datos de eventos recientes de la API de Eventos, con opciones para filtrar y seleccionar métricas en intervalos de tiempo personalizados.

  • ¿Cómo se puede expandir aún más la herramienta?

    Al agregar análisis de entregabilidad, filtros avanzados, almacenamiento en caché de datos y paginación para grandes conjuntos de datos para mejorar el rendimiento y la usabilidad.

  • ¿Qué habilidades o herramientas se requieren para ejecutarlo?

    Conocimiento básico de Python e instalación de requests, dash y pandas. Se requiere una clave API de Bird para extraer datos.

  • ¿Cómo encaja este proyecto en el ecosistema de Bird?

    Ilustra cómo se pueden aprovechar las API abiertas de Bird para crear paneles personalizados y herramientas de informes para equipos o clientes sin acceso a la plataforma completa.

Este script solo roza la superficie de lo que es posible utilizando Python, Plotly Dash y nuestras API.

Bird Metrics API + Dashboarding con Python

Hace casi un año, Tom Mairs, director de éxito del cliente de Bird, escribió una herramienta de correo utilizando Bird APIs. En este post, retomo el trabajo donde lo dejó. Su herramienta permite la transmisión programada de trabajos, pero ¿qué pasa si queremos crear nuestros propios tableros y registros de eventos?

Quizás quiera crear un tablero específico para un grupo empresarial o un tablero orientado al cliente, pero no proporcionar a los usuarios acceso completo a la interfaz de usuario de Bird. Este script apenas toca la superficie de lo que es posible utilizando Python, Plotly Dash y nuestros APIs. Al construir tableros que procesan datos de API de alto volumen, tenga en cuenta que los componentes de infraestructura como DNS pueden convertirse en cuellos de botella - hemos experimentado desafíos de escalamiento DNS de AWS que afectaron nuestras capacidades de procesamiento de datos. Para los entusiastas del flujo visual, también puede explorar la integración de Flow Builder con Google Cloud Functions y Vision API para añadir automatización impulsada por IA a sus canales de procesamiento de datos.

Cuando comencé mi búsqueda en línea, quería encontrar el camino con menos resistencia. Podría haber creado todos los tableros y la interfaz de usuario yo mismo en HTML y Python, sin embargo, después de algunas búsquedas en Google, me encontré con Plotly’s Dash, que se integra fácilmente con Python. Elegí Dash por 2 razones: 1) es de código abierto, y 2) después de leer la documentación, parecía fácilmente personalizable para lo que estaba tratando de hacer. Dash es una biblioteca de código abierto que es ideal para construir e implementar aplicaciones de datos con interfaces de usuario personalizadas. Esto hizo que la creación de una interfaz de usuario fuera extremadamente sencilla. La pregunta entonces se convirtió en, ¿qué tan complejo quería hacer esta aplicación? Cuanto más tiempo pasaba, más funciones quería añadir.

Para el proyecto inicial, quería asegurarme de tener un tablero con métricas personalizables y un marco de tiempo seleccionable. Inicialmente, comencé con un tablero donde solo podía elegir una métrica del menú desplegable. Luego, al recibir comentarios de colegas, afiné un poco el tablero para añadir selección múltiple y títulos de eje. También decidí añadir una pestaña adicional para un registro de eventos. Llegué al punto en que estaba satisfecho con lo que tenía como un buen punto de partida para cualquiera que desee construir sus propios tableros. Para los desarrolladores que quieren integrar datos de webhooks en tiempo real en sus tableros, consulte nuestra guía sobre cómo construir consumidores de webhook con Azure Functions. Por supuesto, puse el proyecto en Github para que lo clonen o desarrollen ramas.

Introducción

Para acceder a esta app, necesitarás asegurarte de que estés ejecutando python 3.10 o superior e instalar las siguientes bibliotecas:

Biblioteca de Python

Propósito

requests

Comunicación API con servicios de Bird

dash

Renderización de UI y panel de control

pandas

Procesamiento de datos y generación de tablas

Luego, introduce tu clave API en App.py y ejecuta la app. Funcionará en http://localhost:8050. Para más información sobre cómo desplegar esto en un servidor público (como AWS), consulta los siguientes recursos:

Creando la página del Dashboard

Primero, inicializa el marco de datos y el tablero. Sin inicializar el tablero, ningún tablero aparecerá en la IU.

df = pd.DataFrame({
    "Count": [0, 0],
    "Time": [0, 0]
})
fig = px.line(df, x="Time", y="Count")

Luego, construye la primera pestaña. Esta es una combinación de una devolución de llamada de la aplicación (para verificar qué pestaña se está utilizando); junto con una función condicional para verificar qué pestaña está actualmente seleccionada. El código a continuación construye solo el tablero en blanco y los elementos de la IU (llegaremos a la pestaña de eventos más adelante). Los elementos dcc son los Componentes de Núcleo Dash y los Componentes HTML que permiten fácilmente que se use HTML en la IU.

html.H2("Analytics Dashboard"),
# Multi-select dropdown
dcc.Dropdown(
    [
        "Count Accepted",
        "Count Admin Bounce",
        "Count Block Bounce",
        "Count Bounce",
        "Count Clicked",
        "Count Delayed",
        "Count Delayed First",
        "Count Delivered",
        "Count Delivered First",
        "Count Delivered Subsequent",
        "Count Generation Failed",
        "Count Generation Rejection",
        "Count Hard Bounce",
        "Count Inband Bounce",
        "Count Initial Rendered",
        "Count Injected",
        "Count Out of Band Bounce",
        "Count Policy Rejection",
        "Count Rejected",
        "Count Rendered",
        "Count Sent",
        "Count Soft Bounce",
        "Count Spam Complaint",
        "Count Targeted",
        "Count Undetermined Bounce",
        "Count Unique Clicked",
        "Count Unique Confirmed Opened",
        "Count Unique Initial Rendered",
        "Count Unique Rendered",
        "Count Unsubscribe",
        "Total Delivery Time First",
        "Total Delivery Time Subsequent",
        "Total Message Volume",
    ],
    id="y-axis",
    multi=True,
    searchable=True,
    placeholder="Select metrics(s)",
),
# Date selector (max date allowed is set to today's date)
dcc.DatePickerRange(
    id="date-picker-range",
    start_date=date(2022, 1, 1),
    end_date=date(2022, 2, 1),
    max_date_allowed=date(
        datetime.today().year,
        datetime.today().month,
        datetime.today().day,
    ),
),
# Graph object
dcc.Graph(id="Emails", figure=fig)

Observa con dash lo fácil que es crear una IU de tablero con un dropdown de selección múltiple y búsqueda. Para desactivar la selección múltiple o la búsqueda, los parámetros para crear un dropdown se pueden modificar fácilmente. Encontré que la parte más compleja de este proyecto fue construir realmente el marco de datos a partir de entradas, además de hacer que el HTML + CSS funcionen correctamente en la IU.

La Time Series Metrics API permite extraer 33 métricas individuales basadas en un rango de fechas/tiempo. Puedes filtrar más profundamente por Dominios, Campañas, Grupos de IP, Dominios de Envío, Subcuentas y especificar la Precisión de los datos de series temporales. Estos filtros adicionales junto con las analíticas de entregabilidad podrían ser una mejora futura para este proyecto (se necesitaría implementar manejo de errores para los clientes que no tienen acceso a analíticas de entregabilidad).

Utilizando y llamando al Metrics API, construyo un tablero con los parámetros seleccionados por el usuario y el periodo de tiempo especificado. El tablero inicializado se actualiza luego.

Vista del Tablero (Time Series Metrics API)

# Build the API call utilizing the parameters provided
params = {
    "from": start_date + "T00:00",
    "to": end_date + "T00:00",
    "delimiter": ",",
    "precision": "day",
    "metrics": joined_values
}
api_url = BASE_URL + "/metrics/deliverability/time-series"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = json.loads(response_API.text)
new_df = pd.json_normalize(response_info, record_path=['results'])
value_array = joined_values.split(",")
# Build out a new dashboard utilizing the new metrics and dates from the updated API call
fig = px.line(
    new_df,
    x=new_df['ts'],
    y=value_array,
    labels={"value": "Count", "variable": "Metric", "ts": "Date"}
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="Count")
return fig

El siguiente es un ejemplo de múltiples métricas seleccionadas y un periodo de tiempo ampliado.


Sparkpost analytics dashboard

Nota: hay muchos elementos integrados automáticamente en el gráfico de dash (hover, zoom, autoescala).

Primero, inicializa el marco de datos y el tablero. Sin inicializar el tablero, ningún tablero aparecerá en la IU.

df = pd.DataFrame({
    "Count": [0, 0],
    "Time": [0, 0]
})
fig = px.line(df, x="Time", y="Count")

Luego, construye la primera pestaña. Esta es una combinación de una devolución de llamada de la aplicación (para verificar qué pestaña se está utilizando); junto con una función condicional para verificar qué pestaña está actualmente seleccionada. El código a continuación construye solo el tablero en blanco y los elementos de la IU (llegaremos a la pestaña de eventos más adelante). Los elementos dcc son los Componentes de Núcleo Dash y los Componentes HTML que permiten fácilmente que se use HTML en la IU.

html.H2("Analytics Dashboard"),
# Multi-select dropdown
dcc.Dropdown(
    [
        "Count Accepted",
        "Count Admin Bounce",
        "Count Block Bounce",
        "Count Bounce",
        "Count Clicked",
        "Count Delayed",
        "Count Delayed First",
        "Count Delivered",
        "Count Delivered First",
        "Count Delivered Subsequent",
        "Count Generation Failed",
        "Count Generation Rejection",
        "Count Hard Bounce",
        "Count Inband Bounce",
        "Count Initial Rendered",
        "Count Injected",
        "Count Out of Band Bounce",
        "Count Policy Rejection",
        "Count Rejected",
        "Count Rendered",
        "Count Sent",
        "Count Soft Bounce",
        "Count Spam Complaint",
        "Count Targeted",
        "Count Undetermined Bounce",
        "Count Unique Clicked",
        "Count Unique Confirmed Opened",
        "Count Unique Initial Rendered",
        "Count Unique Rendered",
        "Count Unsubscribe",
        "Total Delivery Time First",
        "Total Delivery Time Subsequent",
        "Total Message Volume",
    ],
    id="y-axis",
    multi=True,
    searchable=True,
    placeholder="Select metrics(s)",
),
# Date selector (max date allowed is set to today's date)
dcc.DatePickerRange(
    id="date-picker-range",
    start_date=date(2022, 1, 1),
    end_date=date(2022, 2, 1),
    max_date_allowed=date(
        datetime.today().year,
        datetime.today().month,
        datetime.today().day,
    ),
),
# Graph object
dcc.Graph(id="Emails", figure=fig)

Observa con dash lo fácil que es crear una IU de tablero con un dropdown de selección múltiple y búsqueda. Para desactivar la selección múltiple o la búsqueda, los parámetros para crear un dropdown se pueden modificar fácilmente. Encontré que la parte más compleja de este proyecto fue construir realmente el marco de datos a partir de entradas, además de hacer que el HTML + CSS funcionen correctamente en la IU.

La Time Series Metrics API permite extraer 33 métricas individuales basadas en un rango de fechas/tiempo. Puedes filtrar más profundamente por Dominios, Campañas, Grupos de IP, Dominios de Envío, Subcuentas y especificar la Precisión de los datos de series temporales. Estos filtros adicionales junto con las analíticas de entregabilidad podrían ser una mejora futura para este proyecto (se necesitaría implementar manejo de errores para los clientes que no tienen acceso a analíticas de entregabilidad).

Utilizando y llamando al Metrics API, construyo un tablero con los parámetros seleccionados por el usuario y el periodo de tiempo especificado. El tablero inicializado se actualiza luego.

Vista del Tablero (Time Series Metrics API)

# Build the API call utilizing the parameters provided
params = {
    "from": start_date + "T00:00",
    "to": end_date + "T00:00",
    "delimiter": ",",
    "precision": "day",
    "metrics": joined_values
}
api_url = BASE_URL + "/metrics/deliverability/time-series"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = json.loads(response_API.text)
new_df = pd.json_normalize(response_info, record_path=['results'])
value_array = joined_values.split(",")
# Build out a new dashboard utilizing the new metrics and dates from the updated API call
fig = px.line(
    new_df,
    x=new_df['ts'],
    y=value_array,
    labels={"value": "Count", "variable": "Metric", "ts": "Date"}
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="Count")
return fig

El siguiente es un ejemplo de múltiples métricas seleccionadas y un periodo de tiempo ampliado.


Sparkpost analytics dashboard

Nota: hay muchos elementos integrados automáticamente en el gráfico de dash (hover, zoom, autoescala).

Primero, inicializa el marco de datos y el tablero. Sin inicializar el tablero, ningún tablero aparecerá en la IU.

df = pd.DataFrame({
    "Count": [0, 0],
    "Time": [0, 0]
})
fig = px.line(df, x="Time", y="Count")

Luego, construye la primera pestaña. Esta es una combinación de una devolución de llamada de la aplicación (para verificar qué pestaña se está utilizando); junto con una función condicional para verificar qué pestaña está actualmente seleccionada. El código a continuación construye solo el tablero en blanco y los elementos de la IU (llegaremos a la pestaña de eventos más adelante). Los elementos dcc son los Componentes de Núcleo Dash y los Componentes HTML que permiten fácilmente que se use HTML en la IU.

html.H2("Analytics Dashboard"),
# Multi-select dropdown
dcc.Dropdown(
    [
        "Count Accepted",
        "Count Admin Bounce",
        "Count Block Bounce",
        "Count Bounce",
        "Count Clicked",
        "Count Delayed",
        "Count Delayed First",
        "Count Delivered",
        "Count Delivered First",
        "Count Delivered Subsequent",
        "Count Generation Failed",
        "Count Generation Rejection",
        "Count Hard Bounce",
        "Count Inband Bounce",
        "Count Initial Rendered",
        "Count Injected",
        "Count Out of Band Bounce",
        "Count Policy Rejection",
        "Count Rejected",
        "Count Rendered",
        "Count Sent",
        "Count Soft Bounce",
        "Count Spam Complaint",
        "Count Targeted",
        "Count Undetermined Bounce",
        "Count Unique Clicked",
        "Count Unique Confirmed Opened",
        "Count Unique Initial Rendered",
        "Count Unique Rendered",
        "Count Unsubscribe",
        "Total Delivery Time First",
        "Total Delivery Time Subsequent",
        "Total Message Volume",
    ],
    id="y-axis",
    multi=True,
    searchable=True,
    placeholder="Select metrics(s)",
),
# Date selector (max date allowed is set to today's date)
dcc.DatePickerRange(
    id="date-picker-range",
    start_date=date(2022, 1, 1),
    end_date=date(2022, 2, 1),
    max_date_allowed=date(
        datetime.today().year,
        datetime.today().month,
        datetime.today().day,
    ),
),
# Graph object
dcc.Graph(id="Emails", figure=fig)

Observa con dash lo fácil que es crear una IU de tablero con un dropdown de selección múltiple y búsqueda. Para desactivar la selección múltiple o la búsqueda, los parámetros para crear un dropdown se pueden modificar fácilmente. Encontré que la parte más compleja de este proyecto fue construir realmente el marco de datos a partir de entradas, además de hacer que el HTML + CSS funcionen correctamente en la IU.

La Time Series Metrics API permite extraer 33 métricas individuales basadas en un rango de fechas/tiempo. Puedes filtrar más profundamente por Dominios, Campañas, Grupos de IP, Dominios de Envío, Subcuentas y especificar la Precisión de los datos de series temporales. Estos filtros adicionales junto con las analíticas de entregabilidad podrían ser una mejora futura para este proyecto (se necesitaría implementar manejo de errores para los clientes que no tienen acceso a analíticas de entregabilidad).

Utilizando y llamando al Metrics API, construyo un tablero con los parámetros seleccionados por el usuario y el periodo de tiempo especificado. El tablero inicializado se actualiza luego.

Vista del Tablero (Time Series Metrics API)

# Build the API call utilizing the parameters provided
params = {
    "from": start_date + "T00:00",
    "to": end_date + "T00:00",
    "delimiter": ",",
    "precision": "day",
    "metrics": joined_values
}
api_url = BASE_URL + "/metrics/deliverability/time-series"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = json.loads(response_API.text)
new_df = pd.json_normalize(response_info, record_path=['results'])
value_array = joined_values.split(",")
# Build out a new dashboard utilizing the new metrics and dates from the updated API call
fig = px.line(
    new_df,
    x=new_df['ts'],
    y=value_array,
    labels={"value": "Count", "variable": "Metric", "ts": "Date"}
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="Count")
return fig

El siguiente es un ejemplo de múltiples métricas seleccionadas y un periodo de tiempo ampliado.


Sparkpost analytics dashboard

Nota: hay muchos elementos integrados automáticamente en el gráfico de dash (hover, zoom, autoescala).

Creando la Event Details Page

La página de detalles del evento fue un poco más difícil porque no sabía la mejor forma de presentar todas las métricas de los eventos de manera fácil de leer. Consideré agregar parámetros de filtrado a esta página, sin embargo, decidí que eso agregaría una cantidad significativa de tiempo a este proyecto ya que la tabla tendría que ser dinámica (junto con agregar los parámetros, devoluciones de llamada, etc.). Opté por mostrar todos los eventos y colocar la marca de tiempo primero (ya que sin poner la marca de tiempo primero, la tabla no era fácil de leer). Inicialmente, encontré que con solo el HTML en bruto, la tabla era increíblemente difícil para la vista. No había bordes ni diferencias de color para el encabezado versus las filas. Para hacer la tabla más fácil de leer, pude usar CSS dentro de Dash.

Vista de Detalles de Evento (Events API)

La idea para los detalles del evento es casi la misma que el panel de control, excepto que esta vez, llamo a la Events API y traigo todos los eventos. Note que los detalles del evento solo muestran los 10 eventos más recientes (utilizando el parámetro max_rows y el filtrado de la API). Esto se puede incrementar, sin embargo, opté por mostrar los 10 eventos más recientes porque cuanto más eventos se muestran, más tiempo toma la llamada a la API. Una mejora significativa que se podría hacer sería la capacidad de paginación e incluir una página Siguiente / Página Anterior en la interfaz de usuario.

Para desarrollar la pestaña de eventos (página), primero, llamo a la Events API y analizo la respuesta JSON en un marco de datos. Luego ordeno y reordeno el marco de datos para poner la marca de tiempo como la primera columna. Finalmente, construyo la tabla HTML iterando a través del marco de datos.

# Build out and call the events API
params = {
    "events": "delivery,injection,bounce,delay,policy_rejection,out_of_band,open,click,"
              "generation_failure,generation_rejection,spam_complaint,list_unsubscribe,link_unsubscribe",
    "delimiter": ",",
    "page": "1",
    "per_page": "10",
}
api_url = f"{BASE_URL}/events/message"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = response_API.json()
new_df = pd.json_normalize(response_info, record_path=["results"])
max_rows = 10  # Max number of results to show in the events table
# Sort columns and place timestamp as the first column in the table
new_df = new_df.reindex(sorted(new_df.columns), axis=1)
cols = ["timestamp"]
new_df = new_df[cols + [c for c in new_df.columns if c not in cols]]
# Show the new HTML with the events table (note: this table also references table.css)
return html.Div([
    html.H2("Event Details"),
    html.Table([
        html.Thead(
            html.Tr([html.Th(col) for col in new_df.columns], className="table_css")
        ),
        html.Tbody([
            html.Tr([
                html.Td(new_df.iloc[i][col], className="table_css")
                for col in new_df.columns
            ])
            for i in range(min(len(new_df), max_rows))
        ])
    ])
])

Que se ve así en la interfaz de usuario.

Sparkpost event details

La página de detalles del evento fue un poco más difícil porque no sabía la mejor forma de presentar todas las métricas de los eventos de manera fácil de leer. Consideré agregar parámetros de filtrado a esta página, sin embargo, decidí que eso agregaría una cantidad significativa de tiempo a este proyecto ya que la tabla tendría que ser dinámica (junto con agregar los parámetros, devoluciones de llamada, etc.). Opté por mostrar todos los eventos y colocar la marca de tiempo primero (ya que sin poner la marca de tiempo primero, la tabla no era fácil de leer). Inicialmente, encontré que con solo el HTML en bruto, la tabla era increíblemente difícil para la vista. No había bordes ni diferencias de color para el encabezado versus las filas. Para hacer la tabla más fácil de leer, pude usar CSS dentro de Dash.

Vista de Detalles de Evento (Events API)

La idea para los detalles del evento es casi la misma que el panel de control, excepto que esta vez, llamo a la Events API y traigo todos los eventos. Note que los detalles del evento solo muestran los 10 eventos más recientes (utilizando el parámetro max_rows y el filtrado de la API). Esto se puede incrementar, sin embargo, opté por mostrar los 10 eventos más recientes porque cuanto más eventos se muestran, más tiempo toma la llamada a la API. Una mejora significativa que se podría hacer sería la capacidad de paginación e incluir una página Siguiente / Página Anterior en la interfaz de usuario.

Para desarrollar la pestaña de eventos (página), primero, llamo a la Events API y analizo la respuesta JSON en un marco de datos. Luego ordeno y reordeno el marco de datos para poner la marca de tiempo como la primera columna. Finalmente, construyo la tabla HTML iterando a través del marco de datos.

# Build out and call the events API
params = {
    "events": "delivery,injection,bounce,delay,policy_rejection,out_of_band,open,click,"
              "generation_failure,generation_rejection,spam_complaint,list_unsubscribe,link_unsubscribe",
    "delimiter": ",",
    "page": "1",
    "per_page": "10",
}
api_url = f"{BASE_URL}/events/message"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = response_API.json()
new_df = pd.json_normalize(response_info, record_path=["results"])
max_rows = 10  # Max number of results to show in the events table
# Sort columns and place timestamp as the first column in the table
new_df = new_df.reindex(sorted(new_df.columns), axis=1)
cols = ["timestamp"]
new_df = new_df[cols + [c for c in new_df.columns if c not in cols]]
# Show the new HTML with the events table (note: this table also references table.css)
return html.Div([
    html.H2("Event Details"),
    html.Table([
        html.Thead(
            html.Tr([html.Th(col) for col in new_df.columns], className="table_css")
        ),
        html.Tbody([
            html.Tr([
                html.Td(new_df.iloc[i][col], className="table_css")
                for col in new_df.columns
            ])
            for i in range(min(len(new_df), max_rows))
        ])
    ])
])

Que se ve así en la interfaz de usuario.

Sparkpost event details

La página de detalles del evento fue un poco más difícil porque no sabía la mejor forma de presentar todas las métricas de los eventos de manera fácil de leer. Consideré agregar parámetros de filtrado a esta página, sin embargo, decidí que eso agregaría una cantidad significativa de tiempo a este proyecto ya que la tabla tendría que ser dinámica (junto con agregar los parámetros, devoluciones de llamada, etc.). Opté por mostrar todos los eventos y colocar la marca de tiempo primero (ya que sin poner la marca de tiempo primero, la tabla no era fácil de leer). Inicialmente, encontré que con solo el HTML en bruto, la tabla era increíblemente difícil para la vista. No había bordes ni diferencias de color para el encabezado versus las filas. Para hacer la tabla más fácil de leer, pude usar CSS dentro de Dash.

Vista de Detalles de Evento (Events API)

La idea para los detalles del evento es casi la misma que el panel de control, excepto que esta vez, llamo a la Events API y traigo todos los eventos. Note que los detalles del evento solo muestran los 10 eventos más recientes (utilizando el parámetro max_rows y el filtrado de la API). Esto se puede incrementar, sin embargo, opté por mostrar los 10 eventos más recientes porque cuanto más eventos se muestran, más tiempo toma la llamada a la API. Una mejora significativa que se podría hacer sería la capacidad de paginación e incluir una página Siguiente / Página Anterior en la interfaz de usuario.

Para desarrollar la pestaña de eventos (página), primero, llamo a la Events API y analizo la respuesta JSON en un marco de datos. Luego ordeno y reordeno el marco de datos para poner la marca de tiempo como la primera columna. Finalmente, construyo la tabla HTML iterando a través del marco de datos.

# Build out and call the events API
params = {
    "events": "delivery,injection,bounce,delay,policy_rejection,out_of_band,open,click,"
              "generation_failure,generation_rejection,spam_complaint,list_unsubscribe,link_unsubscribe",
    "delimiter": ",",
    "page": "1",
    "per_page": "10",
}
api_url = f"{BASE_URL}/events/message"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = response_API.json()
new_df = pd.json_normalize(response_info, record_path=["results"])
max_rows = 10  # Max number of results to show in the events table
# Sort columns and place timestamp as the first column in the table
new_df = new_df.reindex(sorted(new_df.columns), axis=1)
cols = ["timestamp"]
new_df = new_df[cols + [c for c in new_df.columns if c not in cols]]
# Show the new HTML with the events table (note: this table also references table.css)
return html.Div([
    html.H2("Event Details"),
    html.Table([
        html.Thead(
            html.Tr([html.Th(col) for col in new_df.columns], className="table_css")
        ),
        html.Tbody([
            html.Tr([
                html.Td(new_df.iloc[i][col], className="table_css")
                for col in new_df.columns
            ])
            for i in range(min(len(new_df), max_rows))
        ])
    ])
])

Que se ve así en la interfaz de usuario.

Sparkpost event details

Siguientes pasos

Para alguien que busca crear su propio panel de control o registro de eventos, este es un buen comienzo. Con la personalización aquí, el cielo es el límite.

Como se discutió anteriormente, algunas mejoras futuras que podrían realizarse son:

  • Agregar análisis de entregabilidad al panel de control

  • Agregar más filtros al panel de control

  • Opciones de caché posibles para que el API no se llame cada vez para mostrar las páginas

  • Mejoras de la IU

  • Agregar filtrado y paginación a la página de detalles del evento

Me interesaría recibir cualquier comentario o sugerencias para expandir este proyecto.

~ Zach Samuels, Bird Senior Solutions Engineer

Otras noticias

Leer más de esta categoría

A person is standing at a desk while typing on a laptop.

La plataforma completa AI-native que escala con tu negocio.

© 2026 Bird

A person is standing at a desk while typing on a laptop.

La plataforma completa AI-native que escala con tu negocio.

© 2026 Bird