一个带鸟类 API 的仪表盘工具

电子邮件

·

一个带鸟类 API 的仪表盘工具

关键要点

    • Bird APIs 可以与 Python 和 Plotly Dash 结合来构建强大的交互式仪表板,无需使用完整的 Bird UI。

    • 该项目展示了如何使用 Bird 的指标 API 和事件 API 在自定义 web 应用中可视化指标和事件

    • Plotly Dash 提供了快速的开源框架,用于构建下拉菜单、图表和表格等 UI 元素。

    • 开发人员可以扩展工具,增强可送达性分析、过滤和分页,以创建更加丰富的仪表板。

    • 未来的增强包括缓存、改进 UI 以及与其他 Bird 产品或第三方 API 的集成。

    • 代码库(可在 GitHub 上获取)为任何想要构建 Bird 驱动的仪表板或面向客户的门户的人提供了强大的起点。

Q&A 精华

  • 这个dashboarding项目的目标是什么?

    这展示了开发人员如何使用 Bird 的 API 与 Python 和 Plotly Dash 来创建数据驱动的仪表板,以可视化活动指标和近期事件。

  • 为什么使用 Plotly Dash 来进行 Bird APIs?

    Dash 是开源的,易于定制,且非常适合创建交互式用户界面,无需前端专业知识。

  • 仪表板显示什么?

    它可视化来自Bird的Metrics API的时间序列指标和来自Events API的最新事件数据,具有在自定义时间范围内过滤和选择指标的选项。

  • 该工具如何进一步扩展?

    通过添加可交付性分析、先进的过滤器、数据缓存以及大数据集的分页来提高性能和可用性。

  • 需要什么技能或工具来运行它?

    基本的Python知识和安装requests、dash和pandas。需要一个来自Bird的API密钥来拉取数据。

  • 这个项目如何融入Bird的生态系统?

    它展示了如何利用Bird的开放API为没有访问完整平台的团队或客户创建自定义仪表板和报告工具。

这个脚本只是触及了利用 Python、Plotly Dash 和我们的 API 所能实现的可能性的表面。

Bird Metrics API + 使用Python进行仪表板创建

大约一年前,Bird的客户成功总监Tom Mairs开发了一个使用Bird APIs的邮件工具。在这篇文章中,我接续他的工作。他的工具允许定时传输工作任务,但如果我们想创建自己的仪表板和事件日志呢?

也许我想为某个业务群体创建一个特定的仪表板或一个面向客户的仪表板,但不提供用户对Bird UI的完全访问权限。这个脚本只是触及了使用PythonPlotly Dash我们的API所能实现的可能性的表面。在构建处理高吞吐量API数据的仪表板时,要注意像DNS这样的基础设施组件可能会成为瓶颈——我们曾经遇到过AWS DNS扩展挑战,影响了我们的数据处理能力。对于视觉工作流爱好者,你还可以探索将Flow Builder与Google Cloud Functions和Vision API集成来为数据处理管道添加AI驱动的自动化。

当我开始在线搜索时,我想找到阻力最小的路径。我本可以在HTML和Python中自己创建所有仪表板和UI,然而,经过一些谷歌搜索,我遇到了Plotly的Dash,它与Python轻松集成。我选择Dash的原因有两个:1) 它是开源的,2) 在阅读文档后发现它很容易定制,以实现我想要做的事情。Dash是一个开源库,适合使用定制用户界面构建和部署数据应用。这使得创建UI非常简单。问题变成了,我想把这个应用做得多复杂?我花的时间越多,我想添加的功能就越多。

对于初始项目,我想确保我有一个可定制指标和可选择时间框架的仪表板。最初,我开始使用一个只能从下拉菜单中选择一个指标的仪表板。然后,随着同事的反馈,我稍微改进了一下仪表板,增加了多选择和轴标题。我还决定为事件日志添加一个额外的标签。最后,我对现有的成果感到满意,作为任何希望构建自己仪表板的人的良好起点。对于希望将实时Webhook数据输入到其仪表板的开发人员,请查看我们的关于使用Azure Functions构建Webhook消费者的指南。当然,我把这个项目放在Github上供你克隆或分支。

开始使用

要访问此app,您需要确保运行 python 3.10 或更高版本,并安装以下库:

Python Library

Purpose

requests

与 Bird 服务的 API 通信

dash

UI 和仪表板渲染

pandas

数据处理和表格生成

然后,将您的 API 密钥输入 App.py 并运行该应用程序。它将在 http://localhost:8050 上运行。有关将其部署到公众可访问的服务器(如 AWS)的详细信息,请参阅以下资源:

创建 Dashboard 页面

首先,初始化数据框架和仪表板。如果不初始化仪表板,UI中将不会出现仪表板。

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

接下来,构建出第一个选项卡。这是一个应用回调的组合(以检查正在使用哪个选项卡);以及一个条件函数以检查当前选择了哪个选项卡。下面的代码仅构建空白仪表板和UI元素(稍后我们将讨论事件选项卡)。dcc元素是Dash核心组件HTML组件,使HTML在UI中易于使用。

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)

注意,使用dash创建具有多选、可搜索下拉菜单的仪表板UI是多么简单。要禁用多选或搜索,可以轻松修改创建下拉菜单的参数。我发现这个项目最复杂的部分是从输入中构建实际数据框架,以及让HTML + CSS在UI中正常工作。

时间序列指标API允许根据日期/时间范围提取33个独立指标。您可以通过域、活动、IP池、发送域、子账户进行更深入的过滤,并指定时间序列数据的精度。这些额外的过滤器以及可交付性分析可能是未来对该项目的改进(需要对无法访问可交付性分析的客户实施错误捕获)。

利用和调用指标API,我根据用户选择的参数和指定的时间框架构建了一个仪表板。初始化的仪表板随后更新。

仪表板视图(时间序列指标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

以下是选择多个指标和扩展时间范围的示例。


Sparkpost analytics dashboard

注意:dash图表中自动内置了很多项目(悬停、缩放、自动缩放)。

首先,初始化数据框架和仪表板。如果不初始化仪表板,UI中将不会出现仪表板。

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

接下来,构建出第一个选项卡。这是一个应用回调的组合(以检查正在使用哪个选项卡);以及一个条件函数以检查当前选择了哪个选项卡。下面的代码仅构建空白仪表板和UI元素(稍后我们将讨论事件选项卡)。dcc元素是Dash核心组件HTML组件,使HTML在UI中易于使用。

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)

注意,使用dash创建具有多选、可搜索下拉菜单的仪表板UI是多么简单。要禁用多选或搜索,可以轻松修改创建下拉菜单的参数。我发现这个项目最复杂的部分是从输入中构建实际数据框架,以及让HTML + CSS在UI中正常工作。

时间序列指标API允许根据日期/时间范围提取33个独立指标。您可以通过域、活动、IP池、发送域、子账户进行更深入的过滤,并指定时间序列数据的精度。这些额外的过滤器以及可交付性分析可能是未来对该项目的改进(需要对无法访问可交付性分析的客户实施错误捕获)。

利用和调用指标API,我根据用户选择的参数和指定的时间框架构建了一个仪表板。初始化的仪表板随后更新。

仪表板视图(时间序列指标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

以下是选择多个指标和扩展时间范围的示例。


Sparkpost analytics dashboard

注意:dash图表中自动内置了很多项目(悬停、缩放、自动缩放)。

首先,初始化数据框架和仪表板。如果不初始化仪表板,UI中将不会出现仪表板。

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

接下来,构建出第一个选项卡。这是一个应用回调的组合(以检查正在使用哪个选项卡);以及一个条件函数以检查当前选择了哪个选项卡。下面的代码仅构建空白仪表板和UI元素(稍后我们将讨论事件选项卡)。dcc元素是Dash核心组件HTML组件,使HTML在UI中易于使用。

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)

注意,使用dash创建具有多选、可搜索下拉菜单的仪表板UI是多么简单。要禁用多选或搜索,可以轻松修改创建下拉菜单的参数。我发现这个项目最复杂的部分是从输入中构建实际数据框架,以及让HTML + CSS在UI中正常工作。

时间序列指标API允许根据日期/时间范围提取33个独立指标。您可以通过域、活动、IP池、发送域、子账户进行更深入的过滤,并指定时间序列数据的精度。这些额外的过滤器以及可交付性分析可能是未来对该项目的改进(需要对无法访问可交付性分析的客户实施错误捕获)。

利用和调用指标API,我根据用户选择的参数和指定的时间框架构建了一个仪表板。初始化的仪表板随后更新。

仪表板视图(时间序列指标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

以下是选择多个指标和扩展时间范围的示例。


Sparkpost analytics dashboard

注意:dash图表中自动内置了很多项目(悬停、缩放、自动缩放)。

Creating the 活动详情页面

活动详情页面稍微困难一些,因为我不知道如何以易于阅读的方式展示所有的事件指标。我考虑过在此页面添加过滤参数,但是,我决定这样会为这个项目增加大量的时间,因为表格将需要是动态的(以及添加参数、回调等)。我决定展示所有的事件,并先放置时间戳(如果不先放置时间戳,图表就不容易阅读)。起初,我发现仅使用原始HTML,表格对眼睛来说非常困难。没有边框,也没有标题和行的颜色差异。为了让表格更易读,我能够在Dash中使用CSS。

事件详情视图 (Events API)

事件详情的想法几乎和仪表板一样,除了这次,我调用了Events API并引入了所有事件。请注意,事件详情只显示最新的10个事件(使用max_rows参数和API过滤)。这可以增加,不过,我决定只展示最新的10个事件,因为显示的事件越多,API调用的时间就越长。一个可以做的重大改进是能够在UI中分页并包括下一页/上一页。

要构建事件选项卡(页面),首先,我调用Events API并解析JSON响应到数据帧中。然后我对数据帧进行排序和重新排序,把时间戳作为第一列。最后,我通过遍历数据帧构建HTML表格。

# 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))
        ])
    ])
])

在UI中看起来像这样。

Sparkpost event details

活动详情页面稍微困难一些,因为我不知道如何以易于阅读的方式展示所有的事件指标。我考虑过在此页面添加过滤参数,但是,我决定这样会为这个项目增加大量的时间,因为表格将需要是动态的(以及添加参数、回调等)。我决定展示所有的事件,并先放置时间戳(如果不先放置时间戳,图表就不容易阅读)。起初,我发现仅使用原始HTML,表格对眼睛来说非常困难。没有边框,也没有标题和行的颜色差异。为了让表格更易读,我能够在Dash中使用CSS。

事件详情视图 (Events API)

事件详情的想法几乎和仪表板一样,除了这次,我调用了Events API并引入了所有事件。请注意,事件详情只显示最新的10个事件(使用max_rows参数和API过滤)。这可以增加,不过,我决定只展示最新的10个事件,因为显示的事件越多,API调用的时间就越长。一个可以做的重大改进是能够在UI中分页并包括下一页/上一页。

要构建事件选项卡(页面),首先,我调用Events API并解析JSON响应到数据帧中。然后我对数据帧进行排序和重新排序,把时间戳作为第一列。最后,我通过遍历数据帧构建HTML表格。

# 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))
        ])
    ])
])

在UI中看起来像这样。

Sparkpost event details

活动详情页面稍微困难一些,因为我不知道如何以易于阅读的方式展示所有的事件指标。我考虑过在此页面添加过滤参数,但是,我决定这样会为这个项目增加大量的时间,因为表格将需要是动态的(以及添加参数、回调等)。我决定展示所有的事件,并先放置时间戳(如果不先放置时间戳,图表就不容易阅读)。起初,我发现仅使用原始HTML,表格对眼睛来说非常困难。没有边框,也没有标题和行的颜色差异。为了让表格更易读,我能够在Dash中使用CSS。

事件详情视图 (Events API)

事件详情的想法几乎和仪表板一样,除了这次,我调用了Events API并引入了所有事件。请注意,事件详情只显示最新的10个事件(使用max_rows参数和API过滤)。这可以增加,不过,我决定只展示最新的10个事件,因为显示的事件越多,API调用的时间就越长。一个可以做的重大改进是能够在UI中分页并包括下一页/上一页。

要构建事件选项卡(页面),首先,我调用Events API并解析JSON响应到数据帧中。然后我对数据帧进行排序和重新排序,把时间戳作为第一列。最后,我通过遍历数据帧构建HTML表格。

# 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))
        ])
    ])
])

在UI中看起来像这样。

Sparkpost event details

下一步

对于希望创建自己仪表板或事件日志的人来说,这将是一个好的开始。这里的可定制性使天空为极限。

如上所述,一些未来的改进包括:

  • 在仪表板中添加可送达性分析

  • 为仪表板添加更多过滤器

  • 可能的缓存选项,以便不每次调用API来显示页面

  • UI改进

  • 为事件详细信息页面添加过滤和分页

我有兴趣听取任何反馈或扩展此项目的建议。

~ Zach Samuels, Bird高级解决方案工程师

其他新闻

阅读更多来自此类别的内容

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

完整的AI原生平台,可与您的业务一起扩展。

© 2026 Bird

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

完整的AI原生平台,可与您的业务一起扩展。

© 2026 Bird