虽然我们可以使用busuanzi简单的添加网站统计,但是由于已经添加了Umami 统计,那么就没必要再额外的使用busuanzi做一层计算了,而且Umami 的统计更全面可靠,那么我们如何获取umami的统计信息并添加到网站呢?

有两种方法。

  • 第一种是调用官网API的方法,这一种为了避免Token泄露,需要添加一层中间代理,比如使用CloudFlare Worker或者EdgeOne page。
  • 第二种是采用爬虫策略直接爬取Share链接的信息。

调用官网API的方法

需要注意,这种方法存在限制,官方API有速率限制,而中间层的边缘计算具有次数限制,小量使用完全没问题,但是大量的话会出问题。

云函数代理

我这里使用腾讯EdgeOne的Page Function作为中间层代理,创建目录./edge-functions/umami.js并写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
export async function onRequest(context) {
const UMAMI_BASE = "https://api.umami.is/v1"; // 或你的自建 Umami
const WEBSITE_ID = context.env.UMAMI_WEBSITE_ID;
const TOKEN = context.env.UMAMI_API_TOKEN;

const createdAt = "2025-12-30T17:21:06.019Z";
const start = new Date(createdAt).getTime();
const end = new Date().getTime();

let apiUrl = `${UMAMI_BASE}/websites/${WEBSITE_ID}/stats?startAt=${start}&endAt=${end}`;

try {
const res = await fetch(apiUrl, {
headers: {
Authorization: `Bearer ${TOKEN}`,
Accept: "application/json",
},
});

if (!res.ok) {
return new Response(JSON.stringify({ error: "Umami API error" }), {
status: res.status,
});
}

const data = await res.json();

return new Response(
JSON.stringify({
pageviews: data.pageviews,
visitors: data.visitors,
visits: data.visits,
bounces: data.bounces,
totaltime: data.totaltime,
updatedAt: Date.now(),
}),
{
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods":
"GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Max-Age": "86400",
},
}
);
} catch (e) {
return new Response(
JSON.stringify({ error: e?.message || "Internal error" }),
{ status: 500 }
);
}
}

简单解释一下,获取统计信息主要是访问https://api.umami.is/v1/websites/${WEBSITE_ID}/stats获得,其中 startAtendAt是必须参数,他们是以毫秒为单位的时间戳,createdAt修改为你的网站接入统计的日期,然后endAt使用当前时间戳既可以获取所有时间段的访问量统计,返回值中的pageviews 即为浏览量,而visitors 即为非冗余游客量。当然,访问的时候需要带上Authorization token

如何获取Authorization token

访问这个链接 获取即可,注意保密!

获取API-KEY
获取API-KEY

如何获取网站ID

鼠标点击你的网站名字,新打开的url最后面结尾那一串字符串就是你的网站ID.

获取网站id
获取网站id

edgeOne的演示地址:

然后你就可以在你的页脚处添加一个html 如下:

1
<span id="umami_container_site_pv">本站总访问量<span id="umami_value_site_pv"></span>次, 总访客量<span id="umami_value_site_v"></span></span>

然后写一个javascript脚本来填充数据.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(function () {
const API_URL = "https://landing-page-demo-77qf8sw1.edgeone.app/umami";

const pvEl = document.getElementById("umami_value_site_pv");
const vEl = document.getElementById("umami_value_site_v");

if (!pvEl || !vEl) return;

fetch(API_URL, { cache: "no-store" })
.then((res) => res.json())
.then((data) => {
if (typeof data.pageviews === "number") {
pvEl.textContent = data.pageviews.toLocaleString();
}
if (typeof data.visitors === "number") {
vEl.textContent = data.visitors.toLocaleString();
}
})
.catch(() => {
pvEl.textContent = "-";
vEl.textContent = "-";
});
})();

爬虫抓取

该方案来自博客二叉树树

首先我们启用分享URL

开启分享
开启分享

注意这里的 7PoDRgCzHFTs2vWB ,每个站点都不一样

接着我们请求 https://cloud.umami.is/analytics/us/api/share/7PoDRgCzHFTs2vWB,得到 注意,这里的 us 为你创建的账号区域,美国为us,欧盟为eu.

1
2
3
4
{
"websiteId": "a66a5fd4-98b0-4108-8606-cb7094f380ac",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3ZWJzaXRlSWQiOiJhNjZhNWZkNC05OGIwLTQxMDgtODYwNi1jYjcwOTRmMzgwYWMiLCJpYXQiOjE3NTA4MDIwMzB9.X5GQT5kslh6r25sFlap4Asz1NDA7mN3kcZW8wqbrnBc"
}

再接着我们请求,携带请求头 x-umami-share-token 值为上一步获得的Token

https://cloud.umami.is/analytics/us/api/websites/a66a5fd4-98b0-4108-8606-cb7094f380ac/stats?startAt=0&endAt=1750805999999&unit=hour&timezone=Asia/Hong_Kong&path=eq./posts/cf-fastip/&compare=false

这里解释几个关键Params,其他的照搬

  • startAt:统计开始时间。Unix时间戳,我们填写为0让Umami从1970年开始统计

  • endAt:统计结束时间。Unix时间戳,我们可以使用 Date.now() ,即当前时间,和startAt参数联动即可实现统计总浏览量

  • path:要查询的路径,填写为你的文章页去除了Host的路径,如 /posts/hello 。注意!Umami会将 /posts/hello/posts/hello/ 视为两个不同的路径,请注意你的博客框架是否使用 /。需要使用 eq. 前缀来进行精确匹配,例如 path=eq./posts/hello/

你会得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"pageviews": 1655,
"visitors": 343,
"visits": 411,
"bounces": 183,
"totaltime": 30592,
"comparison": {
"pageviews": 0,
"visitors": 0,
"visits": 0,
"bounces": 0,
"totaltime": 0
}
}

前面已经讲过了,pageviews 即浏览量。 visitors 即访问人数。

那么,重复前面的步骤,我们就可以修改前端的javascript脚本来直接获取该逆向的结果:

依旧创建 html

1
<span id="umami_container_site_pv">本站总访问量<span id="umami_value_site_pv"></span>次, 总访客量<span id="umami_value_site_v"></span></span>

然后写一个javascript脚本来填充数据.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
(function () {
const websiteID = "a66a5fd4-98b0-4108-8606-cb7094f380ac";
const startAt = 0;
const endAt = new Date().getTime();

const API_URL = `https://cloud.umami.is/analytics/us/api/websites/${websiteID}/stats?startAt=${startAt}&endAt=${endAt}`;

const pvEl = document.getElementById("umami_value_site_pv");
const vEl = document.getElementById("umami_value_site_v");

if (!pvEl || !vEl) return;

fetch(API_URL, {
headers: {
"x-umami-share-token":
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3ZWJzaXRlSWQiOiJhNjZhNWZkNC05OGIwLTQxMDgtODYwNi1jYjcwOTRmMzgwYWMiLCJpYXQiOjE3NTA4MDIwMzB9.X5GQT5kslh6r25sFlap4Asz1NDA7mN3kcZW8wqbrnBc",
},
})
.then((res) => res.json())
.then((data) => {
if (typeof data.pageviews === "number") {
console.log(data.pageviews);
pvEl.textContent = data.pageviews.toLocaleString();
}
if (typeof data.visitors === "number") {
console.log(data.visitors);
vEl.textContent = data.visitors.toLocaleString();
}
})
.catch(() => {
pvEl.textContent = "-";
vEl.textContent = "-";
});
})();

因为我想获取全站的总体统计信息,因此只需要两个请求参数startAtendAt即可。

完!