Intent to implement: AMP Access client-side via iframe
See original GitHub issueIntroduction
AMP Access spec provides a way for to lock/unlock content.
At the core of the protocol are three concepts:
- AMP Reader ID. Globally unique session identifier in AMP context.
- Authorization endpoint. A credentialed CORS GET HTTPS endpoint that returns the authorization response that can be used to unlock premium content. It can also be used to render auxiliary sections, such as growls.
- Pingback endpoint. A credentialed CORS POST HTTPS endpoint that confirms the impression.
Metering implementation is specifically described in the Metering section of the AMP Access spec. It suggests that publishers store metering count on their backend system keyed by AMP Reader ID and/or any session information delivered via CORS protocol.
The goal of this ITI is to create a client-side solution that does not require CORS request (or doesn’t always require it). This solution is based on 3p iframes.
Some important considerations when designing this solution:
- Performance. Putting an iframe loading into critical path of document rendering is CPU/memory-heavy and slow. A typical iframe is has a multi-stage loading/execution sequence: load and parse iframe HTML, load main JavaScript, which in turn likely executes a remote XHR. So, this could be as bad as three sequential network requests before the response can be returned. All of these combined could easily reach into > 7s average. Some steps here optimizable, such as JavaScript can be directly bundled into HTML. But it’s hard to require such an optimization.
- Local storage and cookie spaces could be partitioned on some browsers and Safari ITP makes this even less predictable.
The solution
The solution has several components:
- Iframe config and instantiation, parametrized by the AMP Access configuration.
- Iframe communication protocol to invoke authorize and pingback methods.
- AMP-side caching solution with strict one-behind semantics.
- AMP-side timeout semantics with one-behind continuation.
Iframe config and instantiation
This part is very straightforward. It roughly executed as following.
First, the new config extension is provided:
<script id="amp-access" type="application/json">
{
"type": "iframe",
"iframeSrc": "https://pub/iframe",
"iframeVars": [
"EXPRESSION1",
"EXPRESSION2",
...
],
"defaultResponse": {
...
},
// Additional properties.
}
</script>
The iframe is instantiated as following:
const iframeController = createIframe(config.src);
iframeController.connect(config).then(() => {
// Continue to authorization, etc.
});
Iframe communication protocol
AMP will define communication protocol to invoke iframe’s methods, most notably authorize
and pingback
.
Most important, the iframe will establish connection with AMP Runtime via a basic handshake:
- When iframe is ready, it will exchange handshake messages with the AMP Runtime which will include
config
object. - The iframe will first confirm the origin of the AMP page and then perform its internal init/config steps. The iframe then will accept the connection.
- After this, the AMP page and the iframe can communicate freely.
To execute authorization, AMP Runtime will:
- Resolve all variables requested in the
config.iframeVars
. - Send authorize message to the iframe that includes these variables.
- Await the authorize-response response message.
- Apply authorization response as it does now.
To execute pingback, AMP Runtime will:
- Resolve all variables requested in the
config.pingbackVars
. - Send
pingback
message to the iframe that includes these variables.
AMP-side caching with one-behind semantics
So far, this proposal is simple and similar to the AMP Access spec with CORS. However, this section will attempt to address performance issues. We’d like to use the previous response for the next page impression if possible. For the first visit, we also get some of the worst performance factors. So, we would rely on the defaultResponse
to do the initial rendering when cache is not available, which will be assumed to be positive. However, we can speed up the follow up impression. The steps are:
- If the authorization response is available in the local storage of the AMP Runtime and it’s a positive response, use it to open up the page immediately. Delay rendering of any templates, however.
- If the authorization response is not available in the local storage, open the page immediately using the
defaultResponse
. - In either case, in parallel, run the authorization iframe request. Include the previous response as an argument (this could also help with some storage inconsistencies).
- Wait for the new response.
- Store new response in the local storage of the AMP Runtime.
- Render templates, if any, using the new response.
This requires us to define the notion of the positive
response. It means that the authorization response grants read access. We will start by mandating a boolean granted
field in the authorization response.
The cache can have an upper-bound expiration limit, e.g. the cached response is dropped after 7 days.
Thus, only the negative authorizations are render-blocking. Depending on metering quota, this could significantly reduce optimistic render blocks. It’d also normally result in no more than one extra view by the user.
AMP-side timeout semantics and one-behind
In case of previous negative response, the authorization is render-blocking. We normally apply a strict time-out of 3 seconds to authorization requests and we’d like to do the same here.
However, we can do one improvement: even if we timeout the authorization, we can still allow the iframe authorization request to continue and update the cache ones it completes. Thus, the next impression should hopefully proceed faster.
Based on #2970.
Issue Analytics
- State:
- Created 6 years ago
- Comments:13 (8 by maintainers)
@czarnechmurki amp-iframe-api-export.js is just the concatenation of two files:
messenger.js
andiframe-api.js
. The synchronous/dist.3p/current/amp-iframe-api-export.js
is just an example. Concatenation can be done manually, using tools such as rollup, or just takeamp-iframe-api-export.js
file we provide and drop it in your project. You most likely will want to compile these two files into your own JS binary to avoid extra downloads and sync issues - the startup time for this iframe is pretty important so reducing number of binaries would help.We will eventually deploy bundled
messenger.js
andiframe-api.js
as an npm module for those who manage dependencies/compile via npm. Let us know if it’d help you.The #14254 adds configuration parameters, defines authorization response more clearly and adds more docs.