Today, Arknights: Endfield officially begins its open beta. After playing for a while, I thought of importing the gacha data into my own Gacha Analysis App. But maybe because the game just launched, I couldn't find a tool to export gacha data after searching around, so I ended up implementing this feature myself. Below I'll share the main idea; hope it helps if you need to implement this feature.
What's Inside the URL
First, like other games, we can use packet capturing software or some more convenient methods[^1] to obtain a gacha record link like this:
https://ef-webview.hypergryph.com/api/record/char?lang=zh-cn&seq_id={seqId}&pool_type={poolType}&token={token}&server_id={serverId}

Gacha Record Link
Character Banner
For the character banner, we mainly focus on the two parameters pool_type and seq_id:
pool_type is the banner enum value, and currently can only take one of the following banners:
- Departure Recruitment (Beginner Banner):
E_CharacterGachaPoolType_Beginner - Standard Recruitment (Permanent Banner):
E_CharacterGachaPoolType_Standard - Special Recruitment (Limited Banner):
E_CharacterGachaPoolType_Special
Unlike games such as Genshin Impact and Wuthering Waves, Endfield's gacha record link usually includes the seq_id parameter.
// seq_id=26&pool_type=E_CharacterGachaPoolType_Standard
{
"code": 0,
"data": {
"list": [
//...
{
"poolId": "standard",
"poolName": "基础寻访",
"charId": "chr_0019_karin",
"charName": "秋栗",
"rarity": 4,
"isFree": false,
"isNew": false,
"gachaTs": "1769073164712",
"seqId": "21"
}
],
"hasMore": false
},
"msg": ""
}
// pool_type=E_CharacterGachaPoolType_Beginner
{
"code": 0,
"data": {
"list": [
{
"poolId": "beginner",
"poolName": "启程寻访",
"charId": "chr_0022_bounda",
"charName": "萤石",
"rarity": 4,
"isFree": false,
"isNew": false,
"gachaTs": "1769072324787",
"seqId": "20" //该卡池最新的抽卡记录
},
// ...
],
"hasMore": true
},
"msg": ""
}
By observing the records of the two different banners above, we can discover some characteristics of the seq_id parameter:
seq_id (seqId)is an account-level, cross-sub-banner, independent for different banner types incrementing sequence number. All character sub-banners' gacha records share the sameseq_id (seqId)sequence, while weapon sub-banners' gacha records share anotherseq_id (seqId)sequence. Under the same banner type (all character banners or all weapon banners), even if we change the sub-banner type,seq_id (seqId)will not restart counting.- The larger the
seq_id (seqId)number, the later the time and the newer the data. - When the requested link does not include the
seq_idparameter, it will return the latest five records for that banner (i.e., the five records with the largestseqId).
Based on these characteristics, we can understand: In the game's gacha record display page, the process of flipping pages from the first page backwards (from new records to old records) is the process of the seq_id parameter in the gacha record link decreasing.
In the gacha records returned by the link, there will also be a hasMore parameter. It indicates whether there is still data below the smallest seqId in the current returned results, reflecting whether you can still flip to the next page.
Weapon Banner
The weapon banner's API is different from the character banner. The weapon banner needs to use two APIs to obtain data:
Get Weapon Banner List
First, you need to obtain the list of weapon banners where the user has gacha records via the following link:
https://ef-webview.hypergryph.com/api/record/weapon/pool?lang=zh-cn&token={token}&server_id={serverId}
Returned data structure:
{
"code": 0,
"data": [
{ "poolId": "weponbox_1_0_1", "poolName": "熔铸申领" },
{ "poolId": "weaponbox_constant_2", "poolName": "星声申领" }
// ...
],
"msg": ""
}
Here we can see that weapon banners are divided into two types:
- Weapon Limited Banner: The
poolIdformat isweponbox_*(e.g.,weponbox_1_0_1), corresponding to the current UP weapon - Weapon Permanent Banner: The
poolIdformat isweaponbox_constant_*(e.g.,weaponbox_constant_2)
Aside: It's interesting that the prefix of the weapon limited banner's
poolIdis misspelled aswepon; I wonder if it's a historical legacy issue.
Get Weapon Gacha Records
The link format for obtaining specific weapon banner gacha records is slightly different from the character banner gacha record link. The weapon banner gacha record link uses the pool_id parameter instead of the pool_type parameter:
https://ef-webview.hypergryph.com/api/record/weapon?lang=zh-cn&seq_id={seqId}&pool_id={poolId}&token={token}&server_id={serverId}
Its returned data structure is:
{
"code": 0,
"data": {
"list": [
{
"poolId": "weponbox_1_0_1",
"poolName": "熔铸申领",
"weaponId": "wpn_funnel_0010",
"weaponName": "骑士精神",
"weaponType": "E_WeaponType_Wand",
"rarity": 6,
"isNew": true,
"gachaTs": "1769238381938",
"seqId": "47"
},
// ...
],
"hasMore": true
},
"msg": ""
}
The fields of weapon records are slightly different from character records:
weaponId: Weapon IDweaponName: Weapon NameweaponType: Weapon Type (e.g.,E_WeaponType_Sword,E_WeaponType_Wand, etc.)
The seq_id characteristics of the weapon banner are the same as the character banner; all weapon sub-banners share the same seqId sequence.
At this point, we have basically figured out the logic of the Arknights: Endfield gacha record link.
Main Approach
Based on the introduction above, we can conceive a method to obtain all records of all banners using a valid Endfield gacha record link:
Character Banner
- First, take any banner's
pool_type, and make a request withoutseq_idto obtain the latest gacha records with the largestseqIdfor that banner. - Subsequently, use the smallest
seqIdin the returned data as a cursor, traversing all records of that banner until subsequent gacha data is cleaned by the server or reaches the first pull of that banner (hasMore === false). - Switch to another banner's
pool_typeand repeat the first step.
Weapon Banner
- First, call the weapon banner list API to get the weapon banners where the user has data.
- Iterate through each weapon banner, using the
pool_idparameter to get records. - Determine the banner type based on
poolId: if it containsconstantit is a permanent banner, otherwise it is a limited banner.
Code Implementation
// 获取角色池记录
async function fetchCharacterRecords(token: string, serverId: string) {
const poolTypes = [
"E_CharacterGachaPoolType_Beginner",
"E_CharacterGachaPoolType_Standard",
"E_CharacterGachaPoolType_Special",
];
const allRecords = [];
for (const poolType of poolTypes) {
let cursor = null;
let hasMore = true;
while (hasMore) {
const seqIdParam = cursor !== null ? `&seq_id=${cursor}` : "";
const url = `https://ef-webview.hypergryph.com/api/record/char?lang=zh-cn${seqIdParam}&pool_type=${poolType}&token=${encodeURIComponent(token)}&server_id=${serverId}`;
const response = await fetch(url);
const { data } = await response.json();
if (data?.list?.length > 0) {
allRecords.push(...data.list);
hasMore = data.hasMore;
if (hasMore) {
const seqIds = data.list.map(item => Number(item.seqId));
cursor = Math.min(...seqIds);
await new Promise(resolve => setTimeout(resolve, 300));
}
} else {
hasMore = false;
}
}
}
return allRecords;
}
// 获取武器池记录
async function fetchWeaponRecords(token: string, serverId: string) {
const allRecords = [];
const poolListUrl = `https://ef-webview.hypergryph.com/api/record/weapon/pool?lang=zh-cn&token=${encodeURIComponent(token)}&server_id=${serverId}`;
const poolListResponse = await fetch(poolListUrl);
const { data: weaponPools } = await poolListResponse.json();
if (!weaponPools?.length) return allRecords;
for (const pool of weaponPools) {
let cursor = null;
let hasMore = true;
while (hasMore) {
const seqIdParam = cursor !== null ? `&seq_id=${cursor}` : "";
const url = `https://ef-webview.hypergryph.com/api/record/weapon?lang=zh-cn${seqIdParam}&pool_id=${pool.poolId}&token=${token}&server_id=${serverId}`;
const response = await fetch(url);
const { data } = await response.json();
if (data?.list?.length > 0) {
allRecords.push(...data.list);
hasMore = data.hasMore;
if (hasMore) {
const seqIds = data.list.map(item => Number(item.seqId));
cursor = Math.min(...seqIds);
await new Promise(resolve => setTimeout(resolve, 300));
}
} else {
hasMore = false;
}
}
}
return allRecords;
}
Thus, we have implemented obtaining all records of all banners in Arknights: Endfield.
- 1: Since Arknights: Endfield version 1.1, the HGWebview.log log file no longer records gacha record links, causing community scripts to become ineffective. However, you can still assemble a usable gacha record link in one click via JS based on the logged-in loginToken -> oauthToken -> uid -> u8Token on the Hypergryph Network Passport page, but the specific method will not be detailed here.Return1