Calibre’s webhook support allows to receive notifications when a Snapshot is created and when a budget changes status for a given Site. This article explains how to create webhooks manually and with automations.
Create a new webhook by navigating to Settings → Integrations → Add a Webhook for a given Site and pasting in the payload URL (data will be delivered as application/json via HTTP POST).
Choose the type of notifications:
Webhooks (and other integrations) can be managed programmatically using the Node.js API. Check the Integrations API reference for more information.
Webhook data is delivered as JSON (application/json) via HTTP POST to an endpoint of your choice. Here is an example of the output:
1{2 "id": 1485,3 "organisation_id": "your-organisation-id",4 "site_id": "apple",5 "primary_region_id": "us-east-1",6 "ref": null,7 "client": "web",8 "status": "completed",9 "html_url": "https://calibreapp.com/your-organisation-id/apple/snapshots/1485",10 "url": "https://calibreapp.com/api/sites/apple/snapshots/1485.json",11 "created_at": "2018-07-16T23:33:17.970Z",12 "pages": [13 {14 "uuid": "xxx-123-456-789-xxx",15 "name": "iPhone X",16 "status": "completed",17 "endpoint": "https://www.apple.com/iphone-x/",18 "canonical": false,19 "profile": "iPhone 6, 3G connection",20 "profile_uuid": "xxx-123-456-789-xxx",21 "metrics": [22 {23 "name": "speed_index",24 "value": 1409725 },26 {27 "name": "visually_complete",28 "value": 2131729 },30 {31 "name": "lighthouse-seo-score",32 "value": 7533 },34 {35 "name": "lighthouse-best-practices-score",36 "value": 7537 },38 {39 "name": "lighthouse-accessibility-score",40 "value": 8741 },42 {43 "name": "lighthouse-performance-score",44 "value": 1045 },46 {47 "name": "js-parse-compile",48 "value": 688849 },50 {51 "name": "time-to-first-byte",52 "value": 12853 },54 {55 "name": "first-contentful-paint",56 "value": 443357 },58 {59 "name": "first-meaningful-paint",60 "value": 1164961 },62 {63 "name": "firstRender",64 "value": 372465 },66 {67 "name": "dom-size",68 "value": 211069 },70 {71 "name": "estimated-input-latency",72 "value": 85973 },74 {75 "name": "consistently-interactive",76 "value": 2260777 },78 {79 "name": "first-interactive",80 "value": 2124881 },82 {83 "name": "json_body_size_in_bytes",84 "value": 290185 },86 {87 "name": "json_size_in_bytes",88 "value": 174789 },90 {91 "name": "image_body_size_in_bytes",92 "value": 86376593 },94 {95 "name": "image_size_in_bytes",96 "value": 86379097 },98 {99 "name": "font_body_size_in_bytes",100 "value": 402256101 },102 {103 "name": "font_size_in_bytes",104 "value": 404248105 },106 {107 "name": "js_body_size_in_bytes",108 "value": 1815834109 },110 {111 "name": "js_size_in_bytes",112 "value": 425500113 },114 {115 "name": "css_body_size_in_bytes",116 "value": 1329225117 },118 {119 "name": "css_size_in_bytes",120 "value": 93630121 },122 {123 "name": "html_body_size_in_bytes",124 "value": 425563125 },126 {127 "name": "html_size_in_bytes",128 "value": 42739129 },130 {131 "name": "page_wait_timing",132 "value": 1740133 },134 {135 "name": "page_size_in_bytes",136 "value": 2530039137 },138 {139 "name": "page_body_size_in_bytes",140 "value": 5537450141 },142 {143 "name": "asset_count",144 "value": 59145 },146 {147 "name": "onload",148 "value": 22592149 },150 {151 "name": "oncontentload",152 "value": 12595153 }154 ],155 "budget_alerts": null,156 "artifacts": {157 "filmstrip": {158 "thumbs": [159 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1682063.892.jpg",160 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1682532.696.jpg",161 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1685799.232.jpg",162 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1686499.204.jpg",163 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1686899.188.jpg",164 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1687299.172.jpg",165 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1688782.446.jpg",166 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1690182.39.jpg",167 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1691349.01.jpg",168 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1692448.966.jpg",169 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1693715.582.jpg",170 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1703281.866.jpg",171 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1703365.196.jpg",172 "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/1703381.862.jpg"173 ],174 "video": "https://calibre-screenshots-prod.s3.amazonaws.com/05efb55f-0d2b-4c25-afd4-06dd7038fada/video-timeline/screencast.mp4"175 },176 "har": "https://calibre-screenshots-prod.s3.amazonaws.com/5e7ebd8f932d99e2a017fd1e16551221/https___www_apple_com_iphone_x_/har/20180716233507265.json?X-Amz-Expires=3600&X-Amz-Date=20180716T233521Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAITFRYATLYAH7W3VQ/20180716/us-east-1/s3/aws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=be3e0818f2b8c24114d2813faf83b11e3a6d6b8084c84fb44ecde27104215045"177 }178 },179 {180 "uuid": "xxx-123-456-789-xxx",181 "name": "iPhone 6",182 "status": "completed",183 "endpoint": "https://www.apple.com/iphone-6/",184 "canonical": false,185 "profile": "iPhone 6, 3G connection",186 "profile_uuid": "xxx-123-456-789-xxx",187 "metrics": [188 {189 "name": "speed_index",190 "value": 8517191 },192 {193 "name": "visually_complete",194 "value": 11477195 },196 {197 "name": "lighthouse-seo-score",198 "value": 68199 },200 {201 "name": "lighthouse-best-practices-score",202 "value": 68203 },204 {205 "name": "lighthouse-accessibility-score",206 "value": 93207 },208 {209 "name": "lighthouse-performance-score",210 "value": 26211 },212 {213 "name": "js-parse-compile",214 "value": 1501215 },216 {217 "name": "time-to-first-byte",218 "value": 108219 },220 {221 "name": "first-contentful-paint",222 "value": 3470223 },224 {225 "name": "first-meaningful-paint",226 "value": 8449227 },228 {229 "name": "firstRender",230 "value": 2398231 },232 {233 "name": "dom-size",234 "value": 727235 },236 {237 "name": "estimated-input-latency",238 "value": 17239 },240 {241 "name": "consistently-interactive",242 "value": 24364243 },244 {245 "name": "first-interactive",246 "value": 11378247 },248 {249 "name": "json_body_size_in_bytes",250 "value": 1716251 },252 {253 "name": "json_size_in_bytes",254 "value": 1011255 },256 {257 "name": "image_body_size_in_bytes",258 "value": 1968564259 },260 {261 "name": "image_size_in_bytes",262 "value": 1973146263 },264 {265 "name": "font_body_size_in_bytes",266 "value": 346672267 },268 {269 "name": "font_size_in_bytes",270 "value": 348381271 },272 {273 "name": "js_body_size_in_bytes",274 "value": 1077849275 },276 {277 "name": "js_size_in_bytes",278 "value": 271680279 },280 {281 "name": "css_body_size_in_bytes",282 "value": 720939283 },284 {285 "name": "css_size_in_bytes",286 "value": 62227287 },288 {289 "name": "html_body_size_in_bytes",290 "value": 51148291 },292 {293 "name": "html_size_in_bytes",294 "value": 9958295 },296 {297 "name": "page_wait_timing",298 "value": 198299 },300 {301 "name": "page_size_in_bytes",302 "value": 2666403303 },304 {305 "name": "page_body_size_in_bytes",306 "value": 4166888307 },308 {309 "name": "asset_count",310 "value": 73311 },312 {313 "name": "onload",314 "value": 28932315 },316 {317 "name": "oncontentload",318 "value": 7034319 }320 ],321 "budget_alerts": null,322 "artifacts": {323 "filmstrip": {324 "thumbs": [325 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1683338.5.jpg",326 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1683999.304.jpg",327 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1685749.234.jpg",328 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1686815.858.jpg",329 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1686882.522.jpg",330 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1688649.118.jpg",331 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1689749.074.jpg",332 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1691798.992.jpg",333 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1693432.26.jpg",334 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1693732.248.jpg",335 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1694015.57.jpg",336 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1694032.236.jpg",337 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1694098.9.jpg",338 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1694315.558.jpg",339 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1694498.884.jpg",340 "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/1694815.538.jpg"341 ],342 "video": "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/screencast.mp4",343 "gif": "https://calibre-screenshots-prod.s3.amazonaws.com/67ec59cf-0121-4ab7-ab38-e2f4459c40da/video-timeline/screencast.gif"344 },345 "har": "https://calibre-screenshots-prod.s3.amazonaws.com/f477b5ec59c5a357f1f7d756b23c4645/https___www_apple_com_iphone_6_/har/20180716233446500.json?X-Amz-Expires=3600&X-Amz-Date=20180716T233521Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAITFRYATLYAH7W3VQ/20180716/us-east-1/s3/aws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=86e1fe079e3ce90c81bf81a62369c71c03c31640412cd22dce92c1996f4247b7"346 }347 }348 ]349}
1{2 "id": "abc123",3 "url": "http://calibreapp.com/teams/your-team/your-site/budgets/abc123",4 "organisation_id": "your-organisation",5 "site_id": "your-site",6 "name": "Largest Contentful Paint",7 "abbreviated_name": "LCP",8 "value": 3000,9 "formatted": "3s",10 "status": "At risk",11 "threshold": "GreaterThan",12 "generated_at": "2020-09-30T05:33:17.970Z",13 "budgets": [14 {15 "profile": {16 "id": "pr123",17 "name": "Chrome Desktop"18 },19 "page": {20 "id": "p123",21 "name": "Marketing Home",22 "previews": []23 },24 "status": "At risk",25 "value": 2850,26 "formatted": "2.85s"27 },28 {29 "profile": {30 "id": "pr456",31 "name": "MotoG4, 3G connection"32 },33 "page": {34 "id": "p123",35 "name": "Marketing Home",36 "previews": []37 },38 "status": "Met",39 "value": 2400,40 "formatted": "2.4s"41 },42 {43 "profile": {44 "id": "pr789",45 "name": "iPhone, 4G LTE"46 },47 "page": {48 "id": "p123",49 "name": "Marketing Home",50 "previews": []51 },52 "status": "Met",53 "value": 2400,54 "formatted": "2.4s"55 }56 ]57}
Calibre Webhooks can be securely validated using the HMAC cryptographic hash signature (Calibre-HMAC-SHA256-Signature header), which should be used to confirm that the incoming request originates from Calibre.
We recommend using a third party webhook test service, or enabling verbose logging in order to verify the webhooks are delivered in the format as expected. In order to verify the Calibre request, you will need to use the shared secret from Site → Synthetic → Settings → Integrations.
You can find code examples for secret verification below:
1// Example built for express.js, using buffer-equal-constant-time2// Requires environment variable containing the secret: process.env.SECRET_TOKEN34const crypto = require('crypto')5const bufferEq = require('buffer-equal-constant-time')67const verifyCalibreHMAC = (req, res, next) => {8 const payload = req.body()9 const payloadSignature = req.header('Calibre-HMAC-SHA256-Signature')1011 let hmac = crypto.createHmac('sha256', process.env.SECRET_TOKEN)12 hmac.write(payload)13 hmac.end()1415 const signature = hmac.read()1617 if (bufferEq(new Buffer(signature), new Buffer(payloadSignature))) {18 next()19 } else {20 throw new Error('HMAC Signatures do not match')21 }22}2324// Express will downcase headers25app.use(verifyCalibreHMAC)26app.post('/calibre-webhook', (req, res) => {27 res.send('We have a valid hmac signature')28})
1// SECRET_TOKEN is an environment variable23post '/calibre-webhook' do4 request.body.rewind5 payload_body = request.body.read6 verify_signature(payload_body)78 # Safely use the JSON9end1011def verify_signature(payload_body)12 signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body)13 return halt 500, "Signatures didn't match!" unless ActiveSupport::SecurityUtils.secure_compare(signature, request.env['Calibre-HMAC-SHA256-Signature'])14end
In the examples above we have set the original secret as an environment variable. Never commit the secret to source control. We also advise against comparing hashes using the equal comparison operator (==) as it cannot protect against timing attacks.
On this page