Skip to content
This repository has been archived by the owner on Apr 26, 2022. It is now read-only.

AMP configuration #3

Open
dreamflasher opened this issue Apr 12, 2021 · 16 comments
Open

AMP configuration #3

dreamflasher opened this issue Apr 12, 2021 · 16 comments
Labels
enhancement New feature or request

Comments

@dreamflasher
Copy link

dreamflasher commented Apr 12, 2021

What's the correct AMP configuration? (https://amp.dev/documentation/components/amp-analytics/)

Also I am opening a ticket at AMP that they add you as a vendor: ampproject/amphtml#33779

@fsenart
Copy link
Contributor

fsenart commented Apr 13, 2021

I see one big challenge when considering the AMP configuration.
Using the AMP format, the content is cached, which breaks the current mechanism used to track returning visitors within a day (i.e., the IP and UA tuple).
AMP seems to have already addressed user identification when using cookies, but I don't immediately see how this project can fit in the AMP format. We need to investigate more, but at first sight, it doesn't seem promising.

@dreamflasher
Copy link
Author

Thanks a lot for your quick response. That's unfortunate, but I have some hopes with this: https://amp.dev/documentation/components/amp-script/
I'll give it a shot and report back. If this works what we'd need from your end is a javascript that doesn't change. Ideally you'd achieve this by versioning, where eg. https://privera.io/aap.js can point to the latest version, and then you have https://privera.io/aapv1.js etc. for all versions. I think that would be nice from a developer and security perspective anyways.

@dreamflasher
Copy link
Author

I was able to add an amp-script element on the page, so I guess it gets executed. The problem is though that it doesn't seem possible to add the pe-ua="UA-XXX-1" tag, would it be possible on your end to accept the pe-ua also as a get param? Eg. <script src="https://privera.io/aap.js?pe-ua=UA-XXXXX-Y" async></script>

@dreamflasher
Copy link
Author

If I understand correctly it's not possible to access the amp-script tag from the Javascript. But what's inside the amp-script tag can be accessed. Could you add another way to pass the pe-ua in that way? Eg. <script src="https://privera.io/aap.js" async><div pe-ua="UA-XXXXX-Y" /></script>?

@fsenart
Copy link
Contributor

fsenart commented Apr 14, 2021

Thank you so much for your investigations and good news so far.
Allowing to provide configuration via query strings instead of custom attributes is not a big deal per se. Though, this has huge side effects.
The src parameter is the URL of the script in the CDN. As these configurations must be available before calling the collector API, the CDN must, roughly speaking, become dynamic. In other words, it has to inject the given parameters into the script it's serving to mimic the current client-side configuration behavior.
Can you please conduct the following test within AMP and see if the script's src attribute is available:

<!--  test.html -->
<script src="./test.js"></script>
// test.js
console.log(document.currentScript.attributes.getNamedItem("src").value);

I wonder whether AMP doesn't support access to the script at all or it only rejects access to custom attributes. In effect, if the former is true, we can configure the CDN so that the query strings are not interpreted. Then, we can patch the existing configuration retrieval mechanism to support extracting info from the query string at the client side.

@dreamflasher
Copy link
Author

This logs: Uncaught TypeError: Cannot read property 'attributes' of undefined

I extended their amp hello world example and this works:

<amp-script layout="container" script="hello-world" class="sample">
  <button name="XXX" id="hello-inline">Say hello!</button>
</amp-script>

<script id="hello-world" type="text/plain" target="amp-script">
  const button = document.getElementById('hello-inline');

  button.addEventListener('click', () => {
    const h1 = document.createElement('h1');
    h1.textContent = button.attributes[0].value;
    document.body.appendChild(h1);
  });
</script>

I did it as an inline script for faster debugging, but afaik an external script should work the same.

@dreamflasher
Copy link
Author

Without the button stuff and on page load:

<amp-script layout="fixed-height" height="36" script="user-agent-script" class="sample">
  <div>
    Your GA ID is:
    <span id="gaid" class="g-xxx-1"></span>
  </div>
</amp-script>

<script id="user-agent-script" type="text/plain" target="amp-script">
  const span = document.getElementById('gaid');
  span.textContent = span.attributes[1].value;
</script>

@fsenart
Copy link
Contributor

fsenart commented Apr 15, 2021

When using <amp-script>, I think the configuration is awkward if we rely on HTML elements/attributes to retrieve values.
However, we know that dynamic configuration is possible. So we can use a more "conventional" way to provide configuration. That is, first, we include the modified tracker via a <amp-script> tag, then we use a new JS API to configure the tracker via a <script target="amp-script" ...> tag (e.g., aap("config", { ... });).

I may have also found an alternative path that is more straightforward. Let's use the <amp-analytics> tag. It allows us to mimic the current tracking behavior without even including any custom script:

<!DOCTYPE html>
<html amp>
  <head>
    <!-- AMP boilerplate omitted ... -->
    <script
      async
      custom-element="amp-analytics"
      src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"
    ></script>
  </head>
  <body>
    <amp-analytics>
      <script type="application/json">
        {
          "requests": {
            "base": "https:/ENDPOINT/ua/UA-XXXXXXXX-YY/anonymize"
          },
          "transport": {
            "beacon": true,
            "useBody": true
          },
          "triggers": {
            "trackPageview": {
              "on": "visible",
              "request": "base",
              "extraUrlParams": {
                "title": "TITLE",
                "url": "CANONICAL_URL",
                "referrer": "DOCUMENT_REFERRER"
              }
            }
          }
        }
      </script>
    </amp-analytics>
  </body>
</html>

The amount of todos for this solution is pretty small. We need to update the server-side so that JSON payloads are also accepted.

There are also a few drawbacks that can be overcome. In effect, the current js tracker is very conservative in terms of the amount of data leaking from the current and the referrer URL, while AMP doesn't care too much:

  • When using the POST method, AMP doesn't allow for a no-referrer referrer policy. We can overcome this by allowing the GET method server-side and parsing tracking data from the query string.
  • AMP doesn't allow the transformation of the referrer URL before it is sent. So we need to update the server-side API to drop any extra data from the URL before any processing.

Let me know what you think.

@dreamflasher
Copy link
Author

@fsenart Wow thank you so much for having such a detailed look into this, I am amazed!
I am happy with whatever works :)
So yeah, lets just go with the amp-analytics tag.

@dreamflasher
Copy link
Author

@fsenart Let me know if I can be of any help, looking very much forward to the AMP integration.

@fsenart
Copy link
Contributor

fsenart commented Apr 23, 2021

Sorry for the delay. I've been pretty busy these days. I'm on it; keep connected.

@dreamflasher
Copy link
Author

Thanks a lot for the feedback, I can totally understand, and I am just super thankful that you take this extra work besides your normal dayjob. Thank you for this project, I am very eager to try it out, whenever it is ready :)

fsenart added a commit that referenced this issue Apr 26, 2021
- Extract payload from body and query string
- Decode payload as JSON or URL encoded
- Strip query string from document URL
- Strip path and query string from referrer URL

See: #3

Signed-off-by: Farzad Senart <515714+fsenart@users.noreply.github.com>
@fsenart
Copy link
Contributor

fsenart commented Apr 26, 2021

@dreamflasher it's shipped!

If you are using the EE
<!DOCTYPE html>
<html amp lang="en">
  <head>
    <meta charset="utf-8" />
    <script async src="https://cdn.ampproject.org/v0.js"></script>
    <title>Hello, AMPs</title>
    <link
      rel="canonical"
      href="https://amp.dev/documentation/guides-and-tutorials/start/create/basic_markup/"
    />
    <meta name="viewport" content="width=device-width" />
    <script type="application/ld+json">
      {
        "@context": "http://schema.org",
        "@type": "NewsArticle",
        "headline": "Open-source framework for publishing content",
        "datePublished": "2015-10-07T12:02:41Z",
        "image": ["logo.jpg"]
      }
    </script>
    <style amp-boilerplate>
      body {
        -webkit-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
        -moz-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
        -ms-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
        animation: -amp-start 8s steps(1, end) 0s 1 normal both;
      }
      @-webkit-keyframes -amp-start {
        from {
          visibility: hidden;
        }
        to {
          visibility: visible;
        }
      }
      @-moz-keyframes -amp-start {
        from {
          visibility: hidden;
        }
        to {
          visibility: visible;
        }
      }
      @-ms-keyframes -amp-start {
        from {
          visibility: hidden;
        }
        to {
          visibility: visible;
        }
      }
      @-o-keyframes -amp-start {
        from {
          visibility: hidden;
        }
        to {
          visibility: visible;
        }
      }
      @keyframes -amp-start {
        from {
          visibility: hidden;
        }
        to {
          visibility: visible;
        }
      }
    </style>
    <noscript
      ><style amp-boilerplate>
        body {
          -webkit-animation: none;
          -moz-animation: none;
          -ms-animation: none;
          animation: none;
        }
      </style></noscript
    >
    <script
      async
      custom-element="amp-analytics"
      src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"
    ></script>
  </head>
  <body>
    <amp-analytics>
      <script type="application/json">
        {
          "requests": {
            "base": "https://proxy.privera.io/ua/${UA_PROPERTY}/anonymize"
          },
          "vars": {
            "UA_PROPERTY": "UA-XXXXXXXXX-Y"
          },
          "transport": {
            "beacon": true,
            "useBody": true
          },
          "triggers": {
            "trackPageview": {
              "on": "visible",
              "request": "base",
              "extraUrlParams": {
                "type": "page",
                "title": "TITLE",
                "url": "CANONICAL_URL",
                "referrer": "DOCUMENT_REFERRER"
              }
            }
          }
        }
      </script>
    </amp-analytics>
  </body>
</html>
If you are using the CE
<!-- ... -->
      <script type="application/json">
        {
          "requests": {
            "base": "API_ENDPOINT/anonymize"
          },
          "transport": {
            "beacon": true,
            "useBody": true
          },
          "triggers": {
            "trackPageview": {
              "on": "visible",
              "request": "base",
              "extraUrlParams": {
                "type": "page",
                "title": "TITLE",
                "url": "CANONICAL_URL",
                "referrer": "DOCUMENT_REFERRER"
              }
            }
          }
        }
      </script>
<!-- ... -->

Please try the feature and report back any unexpected behavior. I will update the documentation once everything is ok.

@dreamflasher
Copy link
Author

dreamflasher commented Apr 26, 2021

Wow! Amazing! You're the best!
What's the difference between EE and CE?
I'll try them and give feedback asap.

Ah CE=Community Editition/self-hosted, EE=Enterprise

@dreamflasher
Copy link
Author

I removed the boilerplate to create a smaller example that can be used for the docs:

<!DOCTYPE html>
<html amp lang="en">
  <head>
    <meta charset="utf-8" />
    <script async src="https://cdn.ampproject.org/v0.js"></script>      
    <script
      async
      custom-element="amp-analytics"
      src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"
    ></script>
  </head>
  <body>
    <amp-analytics>
      <script type="application/json">
        {
          "requests": {
            "base": "https://proxy.privera.io/ua/${UA_PROPERTY}/anonymize"
          },
          "vars": {
            "UA_PROPERTY": "UA-XXXXXXXXX-Y"
          },
          "transport": {
            "beacon": true,
            "useBody": true
          },
          "triggers": {
            "trackPageview": {
              "on": "visible",
              "request": "base",
              "extraUrlParams": {
                "type": "page",
                "title": "TITLE",
                "url": "CANONICAL_URL",
                "referrer": "DOCUMENT_REFERRER"
              }
            }
          }
        }
      </script>
    </amp-analytics>
  </body>
</html>

@dreamflasher
Copy link
Author

@fsenart You made my day! It works like a charm. Great work, Sir!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants