[{"data":1,"prerenderedAt":900},["ShallowReactive",2],{"docs-\u002Fcontentful":3},{"id":4,"title":5,"body":6,"description":893,"extension":894,"meta":895,"navigation":243,"path":896,"seo":897,"stem":898,"__hash__":899},"docs\u002Fdocs\u002Fcontentful.md","Contentful Integration",{"type":7,"value":8,"toc":875},"minimark",[9,13,17,20,25,28,34,45,50,56,59,65,67,71,78,125,128,149,152,154,158,161,175,178,180,184,187,210,215,318,322,325,342,353,357,368,383,411,415,418,523,527,534,595,597,601,616,627,630,632,636,640,643,737,741,744,804,808,811,871],[10,11,5],"h1",{"id":12},"contentful-integration",[14,15,16],"p",{},"Cachely has first-class support for Contentful. It handles both image and video asset URLs and provides a response transformer that rewrites Contentful CDN URLs in your API responses.",[18,19],"hr",{},[21,22,24],"h2",{"id":23},"supported-url-patterns","Supported URL patterns",[14,26,27],{},"Contentful serves assets from two CDN domains. Cachely handles both:",[14,29,30],{},[31,32,33],"strong",{},"Images:",[35,36,41],"pre",{"className":37,"code":39,"language":40},[38],"language-text","https:\u002F\u002Fimages.ctfassets.net\u002F{spaceId}\u002Fpath\u002Fto\u002Fimage.jpg\n","text",[42,43,39],"code",{"__ignoreMap":44},"",[14,46,47],{},[31,48,49],{},"Videos:",[35,51,54],{"className":52,"code":53,"language":40},[38],"https:\u002F\u002Fvideos.ctfassets.net\u002F{spaceId}\u002Fpath\u002Fto\u002Fvideo.mp4\n",[42,55,53],{"__ignoreMap":44},[14,57,58],{},"Both are rewritten to:",[35,60,63],{"className":61,"code":62,"language":40},[38],"https:\u002F\u002Fyour-tenant.cmsassets.com\u002Fpath\u002Fto\u002Fasset\n",[42,64,62],{"__ignoreMap":44},[18,66],{},[21,68,70],{"id":69},"tenant-setup","Tenant setup",[14,72,73,74,77],{},"When creating your tenant, select ",[31,75,76],{},"Contentful"," as the CMS type and provide your space ID:",[79,80,81,94],"table",{},[82,83,84],"thead",{},[85,86,87,91],"tr",{},[88,89,90],"th",{},"Field",[88,92,93],{},"Value",[95,96,97,105,115],"tbody",{},[85,98,99,103],{},[100,101,102],"td",{},"CMS",[100,104,76],{},[85,106,107,110],{},[100,108,109],{},"Space ID",[100,111,112],{},[42,113,114],{},"your-space-id",[85,116,117,120],{},[100,118,119],{},"Website domain",[100,121,122],{},[42,123,124],{},"your-site.com",[14,126,127],{},"Two origins are automatically configured:",[129,130,131,141],"ul",{},[132,133,134,137,138],"li",{},[31,135,136],{},"Image origin:"," ",[42,139,140],{},"https:\u002F\u002Fimages.ctfassets.net\u002F{spaceId}",[132,142,143,137,146],{},[31,144,145],{},"Video origin:",[42,147,148],{},"https:\u002F\u002Fvideos.ctfassets.net\u002F{spaceId}",[14,150,151],{},"You don't need to set these manually. Cachely resolves them from your space ID.",[18,153],{},[21,155,157],{"id":156},"video-support","Video support",[14,159,160],{},"Contentful serves video and image assets from separate CDN domains. Cachely handles both automatically:",[129,162,163,169],{},[132,164,165,166],{},"Image requests (jpeg, jpg, png, webp, avif, svg, pdf) route to ",[42,167,168],{},"images.ctfassets.net",[132,170,171,172],{},"Video requests (mp4, webm, mov, m4v) route to ",[42,173,174],{},"videos.ctfassets.net",[14,176,177],{},"Range requests for video seeking and streaming are fully supported.",[18,179],{},[21,181,183],{"id":182},"response-transformer","Response transformer",[14,185,186],{},"Install the response transformer to automatically rewrite Contentful asset URLs in your API responses:",[35,188,192],{"className":189,"code":190,"language":191,"meta":44,"style":44},"language-bash shiki shiki-themes github-dark","npm install @synchronized-studio\u002Fresponse-transformer\n","bash",[42,193,194],{"__ignoreMap":44},[195,196,199,203,207],"span",{"class":197,"line":198},"line",1,[195,200,202],{"class":201},"svObZ","npm",[195,204,206],{"class":205},"sU2Wk"," install",[195,208,209],{"class":205}," @synchronized-studio\u002Fresponse-transformer\n",[211,212,214],"h3",{"id":213},"basic-usage","Basic usage",[35,216,220],{"className":217,"code":218,"language":219,"meta":44,"style":44},"language-typescript shiki shiki-themes github-dark","import { transformContentfulAssetUrls } from \"@synchronized-studio\u002Fresponse-transformer\"\n\nconst entries = await contentfulClient.getEntries()\n\nconst transformed = transformContentfulAssetUrls(entries, {\n  spaceId: \"your-space-id\",\n  cmsAssetsUrl: \"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n})\n","typescript",[42,221,222,238,245,270,275,291,303,312],{"__ignoreMap":44},[195,223,224,228,232,235],{"class":197,"line":198},[195,225,227],{"class":226},"snl16","import",[195,229,231],{"class":230},"s95oV"," { transformContentfulAssetUrls } ",[195,233,234],{"class":226},"from",[195,236,237],{"class":205}," \"@synchronized-studio\u002Fresponse-transformer\"\n",[195,239,241],{"class":197,"line":240},2,[195,242,244],{"emptyLinePlaceholder":243},true,"\n",[195,246,248,251,255,258,261,264,267],{"class":197,"line":247},3,[195,249,250],{"class":226},"const",[195,252,254],{"class":253},"sDLfK"," entries",[195,256,257],{"class":226}," =",[195,259,260],{"class":226}," await",[195,262,263],{"class":230}," contentfulClient.",[195,265,266],{"class":201},"getEntries",[195,268,269],{"class":230},"()\n",[195,271,273],{"class":197,"line":272},4,[195,274,244],{"emptyLinePlaceholder":243},[195,276,278,280,283,285,288],{"class":197,"line":277},5,[195,279,250],{"class":226},[195,281,282],{"class":253}," transformed",[195,284,257],{"class":226},[195,286,287],{"class":201}," transformContentfulAssetUrls",[195,289,290],{"class":230},"(entries, {\n",[195,292,294,297,300],{"class":197,"line":293},6,[195,295,296],{"class":230},"  spaceId: ",[195,298,299],{"class":205},"\"your-space-id\"",[195,301,302],{"class":230},",\n",[195,304,306,309],{"class":197,"line":305},7,[195,307,308],{"class":230},"  cmsAssetsUrl: ",[195,310,311],{"class":205},"\"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n",[195,313,315],{"class":197,"line":314},8,[195,316,317],{"class":230},"})\n",[211,319,321],{"id":320},"what-gets-transformed","What gets transformed",[14,323,324],{},"The transformer processes the entire JSON response and rewrites all matching URLs. This includes:",[129,326,327,330,333,336,339],{},[132,328,329],{},"Asset fields",[132,331,332],{},"Rich text embedded assets",[132,334,335],{},"Image fields",[132,337,338],{},"Video fields",[132,340,341],{},"Linked entries with media references",[14,343,344,345,348,349,352],{},"Any URL matching ",[42,346,347],{},"images.ctfassets.net\u002F{spaceId}"," or ",[42,350,351],{},"videos.ctfassets.net\u002F{spaceId}"," is rewritten to your Cachely proxy URL. Query parameters (like Contentful's image transformations) are stripped during rewriting.",[211,354,356],{"id":355},"using-an-environment-variable","Using an environment variable",[14,358,359,360,363,364,367],{},"Set ",[42,361,362],{},"CMS_ASSETS_URL"," in your environment and omit the ",[42,365,366],{},"cmsAssetsUrl"," option:",[35,369,371],{"className":189,"code":370,"language":191,"meta":44,"style":44},"CMS_ASSETS_URL=https:\u002F\u002Fyour-tenant.cmsassets.com\n",[42,372,373],{"__ignoreMap":44},[195,374,375,377,380],{"class":197,"line":198},[195,376,362],{"class":230},[195,378,379],{"class":226},"=",[195,381,382],{"class":205},"https:\u002F\u002Fyour-tenant.cmsassets.com\n",[35,384,386],{"className":217,"code":385,"language":219,"meta":44,"style":44},"const transformed = transformContentfulAssetUrls(entries, {\n  spaceId: \"your-space-id\"\n})\n",[42,387,388,400,407],{"__ignoreMap":44},[195,389,390,392,394,396,398],{"class":197,"line":198},[195,391,250],{"class":226},[195,393,282],{"class":253},[195,395,257],{"class":226},[195,397,287],{"class":201},[195,399,290],{"class":230},[195,401,402,404],{"class":197,"line":240},[195,403,296],{"class":230},[195,405,406],{"class":205},"\"your-space-id\"\n",[195,408,409],{"class":197,"line":247},[195,410,317],{"class":230},[211,412,414],{"id":413},"nuxt-ssr-integration","Nuxt \u002F SSR integration",[14,416,417],{},"For Nuxt or other SSR frameworks, wrap your Contentful client or API layer:",[35,419,421],{"className":217,"code":420,"language":219,"meta":44,"style":44},"\u002F\u002F composables\u002FuseContentfulData.ts\nimport { transformContentfulAssetUrls } from \"@synchronized-studio\u002Fresponse-transformer\"\n\nexport async function useContentfulData() {\n  const entries = await contentfulClient.getEntries()\n\n  return transformContentfulAssetUrls(entries, {\n    spaceId: \"your-space-id\",\n    cmsAssetsUrl: useRuntimeConfig().public.cmsAssetsUrl\n  })\n}\n",[42,422,423,429,439,443,460,477,481,490,499,511,517],{"__ignoreMap":44},[195,424,425],{"class":197,"line":198},[195,426,428],{"class":427},"sAwPA","\u002F\u002F composables\u002FuseContentfulData.ts\n",[195,430,431,433,435,437],{"class":197,"line":240},[195,432,227],{"class":226},[195,434,231],{"class":230},[195,436,234],{"class":226},[195,438,237],{"class":205},[195,440,441],{"class":197,"line":247},[195,442,244],{"emptyLinePlaceholder":243},[195,444,445,448,451,454,457],{"class":197,"line":272},[195,446,447],{"class":226},"export",[195,449,450],{"class":226}," async",[195,452,453],{"class":226}," function",[195,455,456],{"class":201}," useContentfulData",[195,458,459],{"class":230},"() {\n",[195,461,462,465,467,469,471,473,475],{"class":197,"line":277},[195,463,464],{"class":226},"  const",[195,466,254],{"class":253},[195,468,257],{"class":226},[195,470,260],{"class":226},[195,472,263],{"class":230},[195,474,266],{"class":201},[195,476,269],{"class":230},[195,478,479],{"class":197,"line":293},[195,480,244],{"emptyLinePlaceholder":243},[195,482,483,486,488],{"class":197,"line":305},[195,484,485],{"class":226},"  return",[195,487,287],{"class":201},[195,489,290],{"class":230},[195,491,492,495,497],{"class":197,"line":314},[195,493,494],{"class":230},"    spaceId: ",[195,496,299],{"class":205},[195,498,302],{"class":230},[195,500,502,505,508],{"class":197,"line":501},9,[195,503,504],{"class":230},"    cmsAssetsUrl: ",[195,506,507],{"class":201},"useRuntimeConfig",[195,509,510],{"class":230},"().public.cmsAssetsUrl\n",[195,512,514],{"class":197,"line":513},10,[195,515,516],{"class":230},"  })\n",[195,518,520],{"class":197,"line":519},11,[195,521,522],{"class":230},"}\n",[211,524,526],{"id":525},"using-the-generic-transformer","Using the generic transformer",[14,528,529,530,533],{},"You can also use the unified ",[42,531,532],{},"transformCmsAssetUrls"," function:",[35,535,537],{"className":217,"code":536,"language":219,"meta":44,"style":44},"import { transformCmsAssetUrls } from \"@synchronized-studio\u002Fresponse-transformer\"\n\nconst transformed = transformCmsAssetUrls(entries, {\n  cms: \"contentful\",\n  spaceId: \"your-space-id\",\n  cmsAssetsUrl: \"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n})\n",[42,538,539,550,554,567,577,585,591],{"__ignoreMap":44},[195,540,541,543,546,548],{"class":197,"line":198},[195,542,227],{"class":226},[195,544,545],{"class":230}," { transformCmsAssetUrls } ",[195,547,234],{"class":226},[195,549,237],{"class":205},[195,551,552],{"class":197,"line":240},[195,553,244],{"emptyLinePlaceholder":243},[195,555,556,558,560,562,565],{"class":197,"line":247},[195,557,250],{"class":226},[195,559,282],{"class":253},[195,561,257],{"class":226},[195,563,564],{"class":201}," transformCmsAssetUrls",[195,566,290],{"class":230},[195,568,569,572,575],{"class":197,"line":272},[195,570,571],{"class":230},"  cms: ",[195,573,574],{"class":205},"\"contentful\"",[195,576,302],{"class":230},[195,578,579,581,583],{"class":197,"line":277},[195,580,296],{"class":230},[195,582,299],{"class":205},[195,584,302],{"class":230},[195,586,587,589],{"class":197,"line":293},[195,588,308],{"class":230},[195,590,311],{"class":205},[195,592,593],{"class":197,"line":305},[195,594,317],{"class":230},[18,596],{},[21,598,600],{"id":599},"contentful-image-api","Contentful Image API",[14,602,603,604,611,612,615],{},"Contentful's ",[605,606,610],"a",{"href":607,"rel":608},"https:\u002F\u002Fwww.contentful.com\u002Fdevelopers\u002Fdocs\u002Freferences\u002Fimages-api\u002F",[609],"nofollow","Image API"," adds query parameters like ",[42,613,614],{},"?w=800&h=600&fit=fill"," for on-the-fly image transformations. When assets are proxied through Cachely:",[129,617,618,621,624],{},[132,619,620],{},"The edge cache strips query parameters from the cache key for image types",[132,622,623],{},"This means all image transformation variants share the same cache entry",[132,625,626],{},"If you rely on Contentful's Image API transformations, the first cached version will be served for all variants",[14,628,629],{},"If you need different image sizes, apply transformations on the client side or serve each size from a different path.",[18,631],{},[21,633,635],{"id":634},"advanced-options","Advanced options",[211,637,639],{"id":638},"custom-transformers","Custom transformers",[14,641,642],{},"Add additional transformers that run after the default Contentful ones:",[35,644,646],{"className":217,"code":645,"language":219,"meta":44,"style":44},"const transformed = transformContentfulAssetUrls(entries, {\n  spaceId: \"your-space-id\",\n  transformers: [\n    (jsonStr, { base }) => {\n      return jsonStr.replaceAll(\"old-pattern\", \"new-pattern\")\n    }\n  ]\n})\n",[42,647,648,660,668,673,697,723,728,733],{"__ignoreMap":44},[195,649,650,652,654,656,658],{"class":197,"line":198},[195,651,250],{"class":226},[195,653,282],{"class":253},[195,655,257],{"class":226},[195,657,287],{"class":201},[195,659,290],{"class":230},[195,661,662,664,666],{"class":197,"line":240},[195,663,296],{"class":230},[195,665,299],{"class":205},[195,667,302],{"class":230},[195,669,670],{"class":197,"line":247},[195,671,672],{"class":230},"  transformers: [\n",[195,674,675,678,682,685,688,691,694],{"class":197,"line":272},[195,676,677],{"class":230},"    (",[195,679,681],{"class":680},"s9osk","jsonStr",[195,683,684],{"class":230},", { ",[195,686,687],{"class":680},"base",[195,689,690],{"class":230}," }) ",[195,692,693],{"class":226},"=>",[195,695,696],{"class":230}," {\n",[195,698,699,702,705,708,711,714,717,720],{"class":197,"line":277},[195,700,701],{"class":226},"      return",[195,703,704],{"class":230}," jsonStr.",[195,706,707],{"class":201},"replaceAll",[195,709,710],{"class":230},"(",[195,712,713],{"class":205},"\"old-pattern\"",[195,715,716],{"class":230},", ",[195,718,719],{"class":205},"\"new-pattern\"",[195,721,722],{"class":230},")\n",[195,724,725],{"class":197,"line":293},[195,726,727],{"class":230},"    }\n",[195,729,730],{"class":197,"line":305},[195,731,732],{"class":230},"  ]\n",[195,734,735],{"class":197,"line":314},[195,736,317],{"class":230},[211,738,740],{"id":739},"post-transform-hook","Post-transform hook",[14,742,743],{},"Run a function on the parsed result after all URL replacements:",[35,745,747],{"className":217,"code":746,"language":219,"meta":44,"style":44},"const transformed = transformContentfulAssetUrls(entries, {\n  spaceId: \"your-space-id\",\n  postTransform: (data) => {\n    return data\n  }\n})\n",[42,748,749,761,769,787,795,800],{"__ignoreMap":44},[195,750,751,753,755,757,759],{"class":197,"line":198},[195,752,250],{"class":226},[195,754,282],{"class":253},[195,756,257],{"class":226},[195,758,287],{"class":201},[195,760,290],{"class":230},[195,762,763,765,767],{"class":197,"line":240},[195,764,296],{"class":230},[195,766,299],{"class":205},[195,768,302],{"class":230},[195,770,771,774,777,780,783,785],{"class":197,"line":247},[195,772,773],{"class":201},"  postTransform",[195,775,776],{"class":230},": (",[195,778,779],{"class":680},"data",[195,781,782],{"class":230},") ",[195,784,693],{"class":226},[195,786,696],{"class":230},[195,788,789,792],{"class":197,"line":272},[195,790,791],{"class":226},"    return",[195,793,794],{"class":230}," data\n",[195,796,797],{"class":197,"line":277},[195,798,799],{"class":230},"  }\n",[195,801,802],{"class":197,"line":293},[195,803,317],{"class":230},[211,805,807],{"id":806},"error-handling","Error handling",[14,809,810],{},"By default, transform errors are logged as warnings and the original data is returned unchanged. You can provide a custom error handler:",[35,812,814],{"className":217,"code":813,"language":219,"meta":44,"style":44},"const transformed = transformContentfulAssetUrls(entries, {\n  spaceId: \"your-space-id\",\n  onError: (error) => {\n    Sentry.captureException(error)\n  }\n})\n",[42,815,816,828,836,852,863,867],{"__ignoreMap":44},[195,817,818,820,822,824,826],{"class":197,"line":198},[195,819,250],{"class":226},[195,821,282],{"class":253},[195,823,257],{"class":226},[195,825,287],{"class":201},[195,827,290],{"class":230},[195,829,830,832,834],{"class":197,"line":240},[195,831,296],{"class":230},[195,833,299],{"class":205},[195,835,302],{"class":230},[195,837,838,841,843,846,848,850],{"class":197,"line":247},[195,839,840],{"class":201},"  onError",[195,842,776],{"class":230},[195,844,845],{"class":680},"error",[195,847,782],{"class":230},[195,849,693],{"class":226},[195,851,696],{"class":230},[195,853,854,857,860],{"class":197,"line":272},[195,855,856],{"class":230},"    Sentry.",[195,858,859],{"class":201},"captureException",[195,861,862],{"class":230},"(error)\n",[195,864,865],{"class":197,"line":277},[195,866,799],{"class":230},[195,868,869],{"class":197,"line":293},[195,870,317],{"class":230},[872,873,874],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":44,"searchDepth":240,"depth":240,"links":876},[877,878,879,880,887,888],{"id":23,"depth":240,"text":24},{"id":69,"depth":240,"text":70},{"id":156,"depth":240,"text":157},{"id":182,"depth":240,"text":183,"children":881},[882,883,884,885,886],{"id":213,"depth":247,"text":214},{"id":320,"depth":247,"text":321},{"id":355,"depth":247,"text":356},{"id":413,"depth":247,"text":414},{"id":525,"depth":247,"text":526},{"id":599,"depth":240,"text":600},{"id":634,"depth":240,"text":635,"children":889},[890,891,892],{"id":638,"depth":247,"text":639},{"id":739,"depth":247,"text":740},{"id":806,"depth":247,"text":807},"Edge-cache Contentful API responses, keep access tokens server-side, and rewrite image URLs from ctfassets.net automatically.","md",{},"\u002Fdocs\u002Fcontentful",{"title":5,"description":893},"docs\u002Fcontentful","zUPBVFwlS5pwyIbKlINefTkq44t9dSQjYQsz2wTvqpk",1777579477877]