Since Twitch decomissioned API V5, there's no correct way to get the VOD offset for a clip. So I just inspected what the Twitch web app was doing and came up with a super cool hack.
I know this looks really complicated but really it just does two things. First it gets the clip information from the official API, then it uses Twitch GraphQL API to get the offset.
kimne78kx3ncx6brgo4mv6wki5h1ko
is the Client ID that the Twitch web app uses. It can be used to access Twitch's GraphQL API (undocumented & not for public use). The postData
variable contains a request and a sha256Hash
. The sha256Hash
is basically a job ID and may change in the future, but I added the current hash which should work for all clips as of posting this.
const clientId = "" // Put your Twitch Client ID here
const clientSecret = "" // Put your Twitch Client Secret here
// Generates a Twitch Bearer token from your Client ID and Secret
const {
data: {
access_token
}
} = await axios.post(`https://id.twitch.tv/oauth2/token?client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`)
// Gets the clip information from API Helix
const clipId = "CarefulRoundFloofSoonerLater-JShSibkZfWy2CjWR"
const {
data: {
data: [clip]
}
} = await axios.get(`https://api.twitch.tv/helix/clips?id=${clipId}`, {
headers: {
"Authorization": `Bearer ${access_token}`,
"Client-ID": clientId,
}
})
// Gets the clip offset from Twitch GraphQL
const postData = [{
"operationName": "ClipMetadata",
"variables": {
"channelLogin": clip.broadcaster_name,
"clipSlug": clip.id
},
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "ab70572e66f164789c87936a8291fd15e29adc2cea0114b02e60f17d60d6d154"
}
}
}]
const {
data: [{
data: {
clip: {
videoOffsetSeconds
}
}
}]
} = await axios.post("https://gql.twitch.tv/gql", postData, {
headers: {
"Client-ID": "kimne78kx3ncx6brgo4mv6wki5h1ko"
}
})
console.log(videoOffsetSeconds)
Additionally you can now grab comments for the Twitch clip by using the offset and the kimne78kx3ncx6brgo4mv6wki5h1ko
key.
const {
data: comments
} = await axios.get(`https://api.twitch.tv/v5/videos/${clip.video_id}/comments?content_offset_seconds=${videoOffsetSeconds}`, {
headers: {
'Client-ID': 'kimne78kx3ncx6brgo4mv6wki5h1ko'
}
})
console.log(comments)
By default, the previously mentioned /comments
endpoint returns all comments after the provided for the offset, and even some before the offset. You can filter the array by using the following snippet to only show comments that were posted during the clip.
// Get only the comments we need for the clip
const videoOffsetSecondsEnd = videoOffsetSeconds + Math.ceil(clip.duration)
const result = comments.filter(
(comment) => comment.content_offset_seconds <= videoOffsetSecondsEnd && comment.content_offset_seconds >= videoOffsetSeconds
).sort(
(comment) => comment.content_offset_seconds
)