Skip to content

Migrate from Resizer v1 to v2

Purpose

This guide provides an overview of Resizer v2 features and the necessary actions and configurations to start using Resizer v2 within your Arc XP organization

Audience

Developers and technically-savvy users who have worked with Resizer v1 and want to migrate to Resizer v2

Arc XP has moved to a newer version of Resizer (v2) as part of the continuous improvement efforts of our global SaaS platform. Key changes include the following:

  • Simplified authentication. Do not worry about storing secret keys. The authentication token is now included in the auth field of the image ANS whenever you upload an image to Photo Center, and is good for all resize variations. For existing images, you can generate the token on-demand by using the Signing Service API.
  • Integration of SEO-friendly names. Photo Center added a new UI field, SEO Filename, which, if populated, saves as slugified text and can be prepended to the Arc ID in a Resizer URL. This improves your site’s SEO performance.
  • New URL format. Resizer v2 URLs now include the path /resizer/v2/ as the entryway into Arc XP’s new resizing solution.
  • New query parameters. Resizer v2 now uses query parameters instead of path parameters. Third-party libraries or packages are no longer necessary to generate Resizer URLs.
  • Improved processing power and reliability compared to Resizer v1.

Considerations

Before migrating to Resizer v2, consider that your site’s SEO performance might be affected and that some Resizer v1 URLs could remain on your site after migration. This section provides more details on these considerations.

SEO Performance Impact

Migrating to Resizer v2 impacts your SEO performance because moving from v1 to v2 requires images to be re-fetched for the first time, transformed at edge, and cached, resulting in unavoidable latency.

First Hit

First hit is defined as fetching the pristine image and creating the transformed image (derivative) based on the transformation request.

The first hit of Resizer v2 is slower (more latent) than Resizer v1. However, the pros outweigh this single con that may or may not actually affect your SEO performance. Resizer v2 provides the following benefits:

  • More stability than Resizer v1
  • Better turnaround time when it comes to reported issues
  • More efficient developer workflow for creating image derivatives
  • More robust features that can be added in the future

Subsequent Hits

After the first hit impact, subsequent and cached hits with Resizer v2 perform on par with Resizer v1 in terms of latency and output performance. We obtained the following results from testing with a beta partner:

TIMECOUNTLATENCY (ms)SIZE (kb)
v1Feb 6 - Feb 71.31M75ms27.3kb
v2Oct 4 - Oct 5947k75.9ms27.8kb

v1 Image URLs

After you migrate to Resizer v2, it is possible that v1 image URLs may still exist and Google bots are still crawling them. Additionally, the migration may accidentally miss v1 image URLs. Resizer v2 is in General Availability on Production. We are adding a redirect so that v1 URLs automatically redirect to v2.

Requirements

Before taking the migration steps, make sure you meet the following requirements:

  • You are able to run PageBuilder locally and make changes to your feature bundle.

  • You are familiar with content sources and either have custom content sources or are using Themes-provided content sources. See PageBuilder Content Source Documentation.

  • You are familiar with PageBuilder Blocks and are able to update them.

  • You are familiar with environment variables and how to add new variables. See PageBuilder Environment Variables Documentation.

  • For the following examples, we are going to assume there is no image resizing being used for your code and you are rendering the original images.

Migration steps

Take the steps in this section to start using Resizer v2.

1. Determine whether you need a phased migration

Arc XP recommends doing a phased migration to Resizer v2 if you are not using out-of-the-box Arc Blocks (Themes) or if you are using fully custom blocks. This means updating one or few blocks at a time. Since the Themes 2.0 release, all Arc Blocks natively support Resizer v2. If you remained on the upgrade path for your custom blocks, there is no further action needed to migrate to Resizer v2.

A phased migration has the following pros and cons:

Pros:

  • Allows you to monitor your Resizer v2 implementation at scale for any errors

Cons:

  • Slower migration timetable
  • More overhead work required from development teams

If you do wish to do a phased migration to Resizer v2 on a smaller section of your site, see Phased migration from Resizer v1 to Resizer v2 for more details.

2. Add the Resizer v2 environment variables

Resizer v2 requires that you add the following environment variables to your /environment/*.json file.

{
"RESIZER_TOKEN_VERSION": 1,
"SIGNING_SERVICE_DEFAULT_APP": "resizer",
"RESIZER_URL": "{CONTENT_BASE}/resizer/v2/"
}

The RESIZER_TOKEN_VERSION value may vary depending on your organization setup. Make a Get request to the following endpoint of the Delivery API:

{CONTENT_BASE)/v1/organization/hmac-key/resizer

The response includes the field ssm_version. You must use this value for RESIZER_TOKEN_VERSION.

3. Add the auth field to images’ ANS

If you added images to Photo Center before the Resizer v2 or Arc Blocks v2 releases, those images need to be inflated to include the auth field and the resizer token in their ANS.

Arc XP offers the following methods to inflate ANS objects:

  • Make a Get request to the Signing Service API (one request per image, using the image’s encoded URL).
  • Activate PageBuilder’s partial caching (recommended).
  • Include the Signing Service API call in content sources. This approach requires you to take the following steps:
  1. Update existing content sources to use the fetch function (instead of resolve).

  2. Add the logic to the content source to call the Signing Service API when needed.

    The following code block provides an example of an updated content source that uses the updated environment variables:

    import axios from "axios";
    import {
    ARC_ACCESS_TOKEN,
    CONTENT_BASE,
    SIGNING_SERVICE_DEFAULT_APP,
    RESIZER_TOKEN_VERSION,
    } from "fusion:environment";
    const params = {
    id: "text",
    service: "text",
    serviceVersion: "text",
    };
    const fetch = ({
    id,
    service = SIGNING_SERVICE_DEFAULT_APP,
    serviceVersion = RESIZER_TOKEN_VERSION,
    }) =>
    axios({
    url: `${CONTENT_BASE}/signing-service/v2/sign/${service}/${serviceVersion}?value=${encodeURIComponent(id)}`,
    headers: {
    "content-type": "application/json",
    Authorization: `Bearer ${ARC_ACCESS_TOKEN}`,
    },
    method: "GET",
    }).then(({ data: content }) => content);
    export default {
    fetch,
    params,
    http: false,
    // 365 day ttl
    ttl: 31536000,
    };

4. Update custom blocks

This section provides a base example of a block that does not use Resizer v2 and explains the changes that you need to make to the example code in order to use Resizer v2.

Base example (without Resizer v2)

The following example uses ANS content to render an image and headline. The image comes from the Promo Items of Composer, and the headline is the Composer headline:

import React from "react";
import PropTypes from "@arc-fusion/prop-types";
import { useContent } from "fusion:content";
const PromoBlock = ({ customFields }) => {
const content =
useContent({
source: customFields?.itemContentConfig?.contentService ?? null,
query: customFields?.itemContentConfig?.contentConfigValues
? {
...customFields.itemContentConfig.contentConfigValues,
}
: null,
}) || null;
if (!customFields?.itemContentConfig || !content) return null;
return (
<article>
{/*
The image is using Cloudfront directly - which is not the most
optimized way to display an image from Photo Center
Ensure images always go through resizer - see resizer v2
document for details
*/}
<img src={content?.promo_items?.basic?.url} alt="" />
<h2>{content?.headlines?.basic}</h2>
</article>
);
};
PromoBlock.propTypes = {
customFields: PropTypes.shape({
itemContentConfig: PropTypes.contentConfig("ans-item").tag({
group: "Configure Content",
label: "Display Content Info",
}),
}),
};
PromoBlock.label = "Promo Block";
PromoBlock.icon = "paragraph-bullets";
export default PromoBlock;

Example with changes to use Resizer V2

To update the previous example code to use Resizer v2, take the following steps:

  1. Import the updated environment variables:
import { RESIZER_URL, RESIZER_TOKEN_VERSION } from "fusion:environment";
  1. Update the rest of the block to match the following code:

    const promoImage = content?.promo_items?.basic;
    // Get the Image Auth Token from the `auth` object and use the
    // key assigned to auth key 1
    const imageAuth = promoImage.auth[RESIZER_TOKEN_VERSION];
    // Get the _id of the Image
    const imageID = promoImage._id;
    let assetId = imageID;
    // Append the file extension of the image to assetId if present
    if (promoImage.url.split("/").pop().split(".").length > 1) {
    assetId = assetId.concat(".", promoImage.url.split(".").pop());
    }
    return (
    <article>
    <img src={`${RESIZER_URL}/${assetId}?auth=${imageAuth}&width=300`} alt="" />
    <h2>{content?.headlines?.basic}</h2>
    </article>
    );

The img src is now using Resizer v2 path with its auth token and resizer options instead of the raw image URL.

Example with content source

This example calls the Content API for a single item and inflates only the promo images image (Featured Media). ANS objects can contain multiple images, and these could also need inflating:

import axios from 'axios';
import {
CONTENT_BASE,
ARC_ACCESS_TOKEN,
RESIZER_TOKEN_VERSION,
} from 'fusion:environment';
// Import the signing service content source
import signingService from './signing-service';
const params = {
_id: 'text',
};
const fetch = async ({ _id: id, 'arc-site': site }, { cachedCall }) => {
const contentRequest = await axios({
url: `${CONTENT_BASE}/content/v4/?_id=${id}${site ? `&website=${site}` : ''}`,
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${ARC_ACCESS_TOKEN}`,
},
method: 'GET',
}).then(({ data: content }) => content);
// Inflate ANS with token promo items -> basic -> image if there is no auth
if (contentRequest.promo_items.basic.type === 'image' && !contentRequest.promo_items.basic?.auth?.[RESIZER_TOKEN_VERSION]) {
contentRequest.promo_items.basic.auth = contentRequest.promo_items.basic.auth || {};
const signingResponse = await cachedCall(
'image-token',
signingService.fetch, // The fetch method imported from the resizer content source
{ query: { id: contentRequest.promo_items.basic._id }, ttl: 31536000, independent: true },
);
contentRequest.promo_items.basic.auth[RESIZER_TOKEN_VERSION] = signingResponse.hash;
}
return {
...contentRequest,
};
};
export default {
schemaName: 'ans-item',
params,
fetch,
};

The previous code does the following:

  1. Imports the signing service content source. The code assumes the two content sources are in the same directory within your feature bundle.

  2. Imports the RESIZER_TOKEN_VERSION environment variable that enables inflating an ANS object.

  3. Uses the fetch content source pattern with partial caching.

  4. Uses axios client to make the request to the content API With the response from Content API, the code:

    a. Checks if the promo_items.basic.type is an image If so, uses the partial caching feature to make a request to the signing service using the signing service content source.

    b. Passes the image _id to the signing service to get a signed string for the image _id.

    c. Adds the response of the signing service content source to the content API response.

    d. Assigns the signing service response to an auth object using the version number as the object key.

With the content source updated to inflate the ANS object with the auth data, your blocks do not have to handle getting auth tokens. Fetching auth tokens on the server provides better performance, but makes use of caching.

Resizer URL creation

To determine the Resizer URL for your Photo Center images, use these steps:

  1. Determine your Resizer URL.
    • If your site has not yet launched, your Resizer URL follows this model https://{org}-{default-website}-{env}.web.arc-cdn.net/resizer.
    • If your site has launched, your Resizer URL is {website name}/resizer.
  2. Add /v2 to the base Resizer URL: {website name}/resizer/v2.
  3. Take the image ID from the CloudFront URL of the image and append the ID to the Resizer URL from step 2. You can find the CloudFront URL either in ANS or the Photo Center UI path for a published image.
    • Example of image ID from CloudFront URL: SMDVGH3HWRBMRGDZHZFNTCP6EU.jpg
    • Example of Resizer URL with appended ID: {website name}/resizer/v2/SMDVGH3HWRBMRGDZHZFNTCP6EU.jpg
  4. Make a GET request to the Photo API photo/api/v2/{photoId}. Take the Auth token from the image ANS auth field (associated with the image) and paste that as a query parameter at the end of the URL. For example:
{website name}/resizer/v2/SMDVGH3HWRBMRGDZHZFNTCP6EU.jpg?auth=db02a059a34fd56e1041d5513ec2745a54239c848a8b

Non-ANS content

Resizer v2 also supports external images. This section provides an example of a a block that has the ability for an editor to specify an external image through a custom field in PageBuilder Editor.

The following block outputs an image and a headline, provided that both are supplied through PageBuilder Editor. The image uses the imageURL with no resizing.

import React from "react";
import PropTypes from "@arc-fusion/prop-types";
const ManualPromo = ({ customFields }) => {
const { imageURL, headline } = customFields;
if (!imageURL || !headline) return null;
return (
<article>
<img src={imageURL} alt="" />
<h2>{headline}</h2>
</article>
);
};
ManualPromo.propTypes = {
customFields: PropTypes.shape({
imageURL: PropTypes.string,
headline: PropTypes.string,
}),
};
ManualPromo.label = "Manual Promo Block";
ManualPromo.icon = "paragraph-bullets";
export default ManualPromo;

To make the block use Resizer v2, you must update the block to call the signing service content source (see the Example with content source). You must also update the image src to use the Resizer v2 URL, auth token, and resizer parameters. Take the following steps:

  1. Import the RESIZER_URL from the environment variables.

  2. Import the useContent hook from fusion:content to enable content source calls within the block. As the signing service is a content source, you can use the useContent hook to call it as per other content sources. For this case, you must pass the imageURL from the custom fields to the id query param of the content source call.

  3. Update the image src attribute to construct the image src as needed for Resizer v2. As you are calling the signing service content source to get the auth token for Resizer v2, you use content.hash as the value for the auth query param in the image.

The resulting code is as follows:

import React from "react";
import PropTypes from "@arc-fusion/prop-types";
import { RESIZER_URL } from "fusion:environment";
import { useContent } from "fusion:content";
const ManualPromo = ({ customFields = {} }) => {
const { imageURL, headline } = customFields;
const content = useContent({
source: 'signing-service',
query: imageURL ? { id: imageURL } : null,
}) || null;
if (!imageURL || !headline) return null;
return (
<article>
<img src={`${RESIZER_URL}/${imageURL}?auth=${content.hash}&width=300`} alt="" />
<h2>{headline}</h2>
</article>
);
};
ManualPromo.propTypes = {
customFields: PropTypes.shape({
imageURL: PropTypes.string,
headline: PropTypes.string,
}),
};
ManualPromo.label = "Manual Promo Block";
ManualPromo.icon = "paragraph-bullets";
export default ManualPromo;

Further Reading and Resources

To ensure you’re delivering the best experience and images possible to your end users, other optimizations exist for responsive images and, if needed, art-directed images. Arc Blocks v2 handle these optimizations natively.

To learn more about image optimizations, see:

Example Resizer v2 URL

https://clientsite.com/resizer/v2/person-with-red-ball-ABCDEFGHIJKLMNOPQRSTUVWXY.jpg?auth=40b3b900866998ec98c4a286eef727080a10ac968d5eed7bd4a6a084511db6c1&width=500&height=500&quality=80

Example of an image ANS

{
"_id": "6UI63OCUJI5AW6IHRW46XWAAPU",
"additional_properties": {
...
},
"auth": {
"1": "40b3b900866998ec98c4a286eef727080a10ac968d5eed7bd4a6a084511db6c1"
},
...
"seo_filename": "person-with-red-ball",
"url": "https://cloudfront-us-east-1.images.arcpublishing.com/6UI63OCUJI5AW6IHRW46XWAAPU.jpg",
"type": "image"
}