# Hyperflow v2.0

A micro-services-based reverse-proxy infrastructure that makes your Webflow-hosted sites far more powerful.

{% hint style="success" %}
In Apr 2025, we've released Hyperflow v2.0 ( HF2 ), which has been re-architected to support a number of new capabilities.
{% endhint %}

## What is Hyperflow?&#x20;

**Hyperflow is Sygnal's rapidly expanding framework of reverse-proxy-based services, specifically designed for Webflow-hosted sites.**

We have a huge range of capabilities including;

* Hyperspeed edge-caching and performance enhancements for your sites &#x20;
* Custom files & folder, including Apple Pay and other .well-known compliance files&#x20;
* Webflow User Accounts enhancements- full user info anywhere, anytime, throughout your site&#x20;
* Live integration of external resources, like Google Docs content directly on your pages&#x20;
* Custom path rewriting&#x20;
* Split Localized Webflow sites into multiple Locale-spedific domains  &#x20;
* Middleware custom APIs for secure access to your favorite APIs and services.&#x20;

There are so many things, we're too excited to tell you about.

## What's New in HF2?&#x20;

### Microservices&#x20;

**Hyperflow 2.0** uses a Cloudflare-based infrastructure and is architected as collection of individually configurable microservices. &#x20;

Benefits;&#x20;

* More flexible service pipeline.  Multiple services can work on the same page to deliver the same site.&#x20;
* Both global and service-level configurations&#x20;
* Individual micro-service code repos, teams, and upgrade cycles&#x20;

### Logging

We now support logging to external services, currently Posthog. Other logging providers can be supported on request.&#x20;

{% hint style="success" %}
One of the primary benefits of this approach is that each Hyperflow App can now be managed in a separate Github repo, with separate development teams working on them.&#x20;
{% endhint %}


# What's New?

What's new in Hyperflow?

## Posthog Logging Support

## Hyperflow LLMS

Generate and deliver LLMS files on your Webflow site automatically, including;

* `/llms.txt` , based on a special Webflow page that you control in the designer.
* `/*.md` markdown files for every page on your site &#x20;

[Learn more](/apps/hyperflow-llms)&#x20;

## Hyperflow v2.0

**Released!**  Hyperflow 2 uses our same Cloudflare infrastructure but is now re-architected as a microservices infrastructure, so that individual Hyperflow Apps can be separately configured, maintained, and upgraded.&#x20;

{% hint style="success" %}
One of the primary benefits of this approach is that each Hyperflow App can now be managed in a separate Github repo, with separate development teams working on them.&#x20;
{% endhint %}

## Hyperflow Files

Serve plain text files at any path. Designed for verification services like Apple Pay.&#x20;

## Sygnal Hyperspeed

As of April 2024, **Sygnal Hyperspeed** is a fully mature product with new releases happening several times a month.

It offers full asset coverage including images, video, CMS assets, on your content including foreground, background, and responsive images throughout your site.&#x20;

{% hint style="info" %}
See specific [Hyperspeed releases](/hyperspeed/hyperspeed-releases) here.
{% endhint %}

### Monitoring & Maintenance Program

In June 2024, we've launched our [monitoring & maintenance](/hyperspeed/hyperspeed-monitoring-and-maintenance) program which allows you to see the performance benefits you're getting and to ensure maximum uptime for your site. Our team is continually looking for improvements- even SEO advantages that we can add to your site.&#x20;


# Overview

All Hyperflow 2 apps are managed by a core infrastructure called the Hyperflow Controller.&#x20;

In addition to managing configurations and dispatching, it offers certain functionality on its own.&#x20;

Current this is divided into two categories;&#x20;

## Basic Site Enhancements

* [SEO Enhancements](/core/seo-enhancements)&#x20;
* [Cleanup](/core/seo-enhancements)&#x20;
* Versioning indication as a comment&#x20;

<figure><img src="/files/r8ia55SWMCKIKUKO684j" alt=""><figcaption></figcaption></figure>

## API

* Hyperflow's own API &#x20;

## Logging&#x20;

* Logging activity to an external provider&#x20;


# SEO Enhancements

Hyperflow 2 SEO Enhancements

## HTML Enhancements

### Adds Open Graph \<og:url>

Automatically adds the `<og:url>` based on the Webflow canonical.&#x20;

### Removes Conditionally Hidden Elements&#x20;

Anything that is conditionally hidden is still in the page and can pollute SEO. To prevent this we remove these elements fully.&#x20;

## HTTP Response Header Enhancements

Last-Modified

<https://en.wikipedia.org/wiki/List_of_HTTP_header_fields>

## Performance Enhancements

### Edge Caching Support&#x20;

For blazingly fast HTML delivery, Hyperflow can leverage edge caching as a configuration option.&#x20;

## Sitemap.xml Enhancements&#x20;

{% hint style="info" %}
Not automatically part of Hyperflow core, but this can be added for a client implementation. Each client implementation here is different.&#x20;
{% endhint %}

<https://www.sitemaps.org/protocol.html>

```
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset> 
```

<https://www.v9digital.com/insights/sitemap-xml-why-changefreq-priority-are-important/>

### changefreq

### lastmod

### priority

### Sitemap Index

In larger sitemaps, it's possible to split the Sitemap into chunks.&#x20;

{% hint style="info" %}
This can be beneficial for sites where we are doing modifications like `<lastmod>` because of the traffic to the KV store to retrieve those dates. In this way we can separate e.g. by CMS Collection.&#x20;
{% endhint %}

## Technical Notes

Webflow includes a comment in its published HTML at the top of the page, e.g.;&#x20;

```
<!-- Last Published: Tue Apr 22 2025 02:47:00 GMT+0000 (Coordinated Universal Time) -->
```

The date shown here is the date the site was last published.  In the case of a CMS page, where the CMS item has been republished, it does not update to reflect that.&#x20;


# Hyperflow 2 API

The Hyperflow API is directly integrated into your site.

Access it using your default domain name, e.g. `https://www.mysite.com/.hf`&#x20;

{% hint style="success" %}
Since Webflow does not permit pages or paths that begin with a period `.`, there is no risk of conflicting with an existing Webflow page.&#x20;
{% endhint %}

## Get Hyperflow Overview

```
GET /.hf
```

Indicates the Hyperflow version and all installed apps.&#x20;

## Hyperflow Core API Calls&#x20;

All Hyperflow Core API calls follow the pattern;&#x20;

```
/.hf/api/*
```

## Hyperflow Version

```
GET /.hf/api/version
```

Returns the version number only, designed for app use.&#x20;

## Specific App API Calls

Fall under the app-name, e.g. `wfx` .

Each app will have a distinct API and its own docs.&#x20;

```
/.hf/(app-name)/* 
```

## Hyperflow Info

On your HF2 enabled Webflow site, just add `/.hf` to the end of your domain name, like this;&#x20;

e.g. <https://www.sygnal.com/.hf>

You'll get a version report.&#x20;

```
Sygnal Hyperflow v2.0.2.0

Docs:
https://hyperflow.sygnal.com/
```

<figure><img src="/files/29txaCwvmO7UxfkAx4YN" alt=""><figcaption></figcaption></figure>


# Logging

Hyperflow 2.0 supports Posthog logging so that you can determine who is using the various Hyperflow services pages.&#x20;

Each service can individually log its activity to a single defined Posthog account.

{% hint style="success" %}
This is configured in environment variables as POSTHOG\_API\_KEY and is the public-facing Posthog ingest ID that begins with `phc_`&#x20;
{% endhint %}


# Hyperflow Monitor

Monitor your automations to ensure they're running.

**Most website designers think in terms of a website and web hosting.  The reality is that modern websites are often an amalgam of services, and you have to begin thinking of it as a&#x20;*****system*****.**&#x20;

Many *systems* rely on multiple external pieces such as;&#x20;

* Automations ( Zapier, Make, n8n, etc. )
* External API's
* External file stores, such as S3 buckets
* External databases&#x20;
* External datafeeds ( RSS, XML, etc. )&#x20;

{% hint style="info" %}
There are a lot of points of failure where things can go wrong and your site will not function correctly.&#x20;
{% endhint %}

## Terminology

* **Monitor.** An individual monitor, defined by a URL and alerting rules.
* **Alerting Profile.**  A definition of how to alert you.&#x20;

## Monitor Definition

* **Name.**  A name for the monitor, for alerting and reporting.
* **ID.**  The monitor's unique identifier. This is usually an arbitrary UUID that you can create anywhere.&#x20;
* **Interval ( mins ).**  The monitoring interval.
* **Expires.**  Timeout when the next alert would occur.
* Message. &#x20;
* Event Alert.  Alert handler for events.&#x20;
* Expired Alert.  Alert handler for expired alerts. &#x20;

## Usage Notes

At Sygnal we often use Hyperflow Monitor for multiple purposes-

For example, let's suppose we have an important purchasing feature on a client site.  Hyperflow Monitor can;

* Alert us every time a transaction is made, with a positive *cha-ching!*  notification&#x20;
* Alert us any time a transaction hasn't been seen for specified period of time, so that we can check the system and ensure everything is working &#x20;


# API

The Hyperflow Monitor API

{% hint style="info" %}
Monitor ID's can be any unique arbitrary string, but we recommend UUIDs.\
<https://www.uuidgenerator.net/version4>&#x20;

*For the API calls, ensure it is properly URL encoded.*&#x20;
{% endhint %}

## Get monitor info

<mark style="color:green;">`GET`</mark> `/(monitor-id)`

Returns the information on the specified monitor.&#x20;

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
    "name": "Monitor 1",
    "id": "8ad4a5dc-5481-4973-aa99-e0183904528d",
    "interval": 2880,
    "message": null,
    "alert_ping": null,
    "alert_timeout": null,
    "timeout": "2024-08-10T22:07:55.173Z"
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "status": "error",
  "message": "Invalid request"
}
```

{% endtab %}

{% tab title="404" %}

```json
{
  "status": "error",
  "message": "No match found"
}
```

{% endtab %}
{% endtabs %}

## Ping monitor&#x20;

<mark style="color:green;">`GET`</mark> `/(monitor-id)/ping`

Records the ping event.&#x20;

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "status": "success",
  "message": "Operation completed successfully.",
  "data": {
    "timeout": "2024-08-10T22:07:55.173Z" 
  }
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "status": "error",
  "message": "Invalid request"
}
```

{% endtab %}

{% tab title="404" %}

```json
{
  "status": "error",
  "message": "No match found"
} 
```

{% endtab %}

{% tab title="500" %}

```json
{
  "status": "error",
  "message": "Failed to update monitor"
}
```

{% endtab %}
{% endtabs %}

## Test monitor alerting

<mark style="color:green;">`GET`</mark> `/(monitor-id)/test`

Performs alerting on both ping and timeout.&#x20;

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "status": "success",
  "message": "Test alert sent"
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "status": "error",
  "message": "Invalid request"
}
```

{% endtab %}

{% tab title="404" %}

```json
{
  "status": "error",
  "message": "Monitor not found"
} 
```

{% endtab %}

{% tab title="500" %}

```json
{
  "status": "error",
  "message": "Failed to send alert"
}
```

{% endtab %}
{% endtabs %}

## Add monitor&#x20;

<mark style="color:green;">`POST`</mark> `/`

Create a new monitor

**Body**

<table><thead><tr><th width="201">Name</th><th width="127">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>id</code></td><td>string</td><td>( optional ). If unspecified, monitor instance is assigned a UUID</td></tr><tr><td><code>name</code></td><td>string</td><td>Name of the monitor</td></tr><tr><td><code>interval</code></td><td>number</td><td>Timeout interval ( in mins ) </td></tr><tr><td><code>message</code></td><td>string</td><td>The message to send</td></tr><tr><td><code>alert_ping</code></td><td>string</td><td>The alerting profile to use</td></tr><tr><td><code>alert_timeout</code></td><td>string</td><td>The alerting profile to use for timeout events</td></tr></tbody></table>

Example;

```json
{
    "name": "Test",
    "interval": 2880,
    "message": "A new booking was made",
    "alert_ping": "sygnal-pushbullet",
    "alert_timeout": "sygnal-pushbullet"
}
```

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "status": "success",
  "message": "Test alert sent",
  "data": {
    "id": "8ad4a5dc-5481-4973-aa99-e0183904528d" 
  }
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "status": "error",
  "message": "Invalid request"
}
```

{% endtab %}

{% tab title="404" %}

```json
{
  "status": "error",
  "message": "Monitor not found"
} 
```

{% endtab %}

{% tab title="500" %}

```json
{
  "status": "error",
  "message": "Failed to send alert"
}
```

{% endtab %}
{% endtabs %}

## Update monitor&#x20;

<mark style="color:green;">`PATCH`</mark> `/(monitor-id)`

Update a monitor

**Body**

<table><thead><tr><th width="201">Name</th><th width="127">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td>string</td><td>Name of the monitor</td></tr><tr><td><code>interval</code></td><td>number</td><td>Timeout interval ( in mins ) </td></tr><tr><td><code>message</code></td><td>string</td><td>The message to send</td></tr><tr><td><code>alert_ping</code></td><td>string</td><td>The alerting profile to use</td></tr><tr><td><code>alert_timeout</code></td><td>string</td><td>The alerting profile to use for timeout events</td></tr></tbody></table>

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "status": "success",
  "message": "Monitor updated" 
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "status": "error",
  "message": "Invalid request"
}
```

{% endtab %}

{% tab title="404" %}

```json
{
  "status": "error",
  "message": "Monitor not found"
} 
```

{% endtab %}

{% tab title="500" %}

```json
{
  "status": "error",
  "message": "Failed to send alert"
}
```

{% endtab %}
{% endtabs %}


# Alert Setup

ALERTS KV Store

Key&#x20;

`sygnal-pushbullet`&#x20;

Value:&#x20;

```
{
  "api-key": "..."
}
```


# Hyperflow Locale-Specific Domains

Split your Webflow Localized site into separate domains for improved local SEO.

**Webflow localization is very useful, but it can only deliver the site's localed content in a locale-specific path structure.**

For example, a site with English as the primary locale, and French and German as alternate locales might be delivered as;&#x20;

| Locale               | Homepage | e.g. Path   | e.g. Localized Path |
| -------------------- | -------- | ----------- | ------------------- |
| English ( primary )  | /        | /contact    | /contact            |
| French ( alternate ) | /fr      | /fr/contact | /fr/contactez-nous  |
| German ( alternate ) | /de      | /de/contact | /de/kontakt         |

This works and is SEO friendly, but it loses the benefit of a Country-Code Top-Level Domain ( ccTLD ) which has an intrinsic locale&#x20;

{% hint style="success" %}
Websites utilizing ccTLDs often experience better rankings in country-specific search results. For example, a `.fr` domain is more likely to rank higher in searches conducted from France compared to a generic `.com` domain, assuming other SEO factors are equal.
{% endhint %}

Ideally this makes more sense for some sites;&#x20;

<table><thead><tr><th width="176">Locale</th><th>e.g. Path</th><th>e.g. Localized Path</th></tr></thead><tbody><tr><td>English ( primary )</td><td>https://www.mysite.com/contact</td><td>https://www.mysite.com/contact</td></tr><tr><td>French ( alternate )</td><td>https://www.mysite.fr/contact</td><td>https://www.mysite.fr/contactez-nous</td></tr><tr><td>German ( alternate )</td><td>https://www.mysite.de/contact</td><td>https://www.mysite.de/kontakt</td></tr></tbody></table>

This works and is SEO friendly, but it loses the benefit of a Country-Code Top-Level Domain ( ccTLD ) which has an intrinsic locale&#x20;

{% hint style="info" %}
It's important to distinguish between language and location.  Webflow is good at supporting language translation but it is not good at supporting locations.  If you target a site at both the UK and the US, it's likely that most browsers in both locations will try to access /en  even when you have /en-GB  pages defined.&#x20;

This is because auto-routing looks at the browser's language, but does not do GeoIP lookups to identify where the user is currently located.&#x20;
{% endhint %}

## Video Discussion &#x20;

{% embed url="<https://www.loom.com/share/30ed0d74715041678d24d485c971b3e9>" %}

## Goals

* Split a Webflow-localized site into discrete domains, one locale per domain, e.g. mysite.com ( EN ), mysite.fr ( French ), mysite.co.jp ( Japanese )&#x20;
  * All page level content
  * All navigation
* Fully support SEO
  * Split and cross-reference sitemaps&#x20;
  * Reflect alt hreflang URL changes&#x20;
  * Redirect all original localization paths by 301, to the new sites to preserve SEO&#x20;
  * Handle all internal linking, e.g. direct links to `/fr/...` should link to the appropriate site.&#x20;
  * Support the locale switcher&#x20;
* Support intentional content gaps, e.g. untranslated CMS items or static pages&#x20;
* Maintain all centralized publishing, API support, integrations, CMS, etc as normal&#x20;

## Future

{% hint style="info" %}
Not yet tested.&#x20;
{% endhint %}

* Support Localization Pro's localized paths &#x20;

Possible;&#x20;

* Auto-routing. based on browser location & language&#x20;

## Notes&#x20;

Locale-Specific Domains & Sub-Domains

<https://discourse.webflow.com/t/seperate-domains-for-localisations/262898/4>

Return requested pages for the specific requested locale /path/...

Modify alt lang href

Suppress irrelevant locale paths ( 404s )&#x20;

* May be possible to redirect them to the alt ccTLD URL&#x20;

Canonicals&#x20;

Sitemap.xml

Links

e.g. /de/menu

Locale switcher modify alt page paths to other ccTLD sites&#x20;

## Path fixes

CMS paths are always

* Determine current locale, and whether it's an alt locale&#x20;

Fix paths so that they are e.g. `/blog` and not `/fr/blog` on the `domain.fr` custom domain.&#x20;

## Language Link cross-references

Rel="alternate" Links

Adjust these to the domain per locale

Splitting Sitemaps by Locale

Research these;

It appears that for rel="alternate" links in the sitemap, you can reference a different domain legitimately;&#x20;

```xml
<!-- Sitemap for example.com -->
<url>
  <loc>https://www.example.com/page1</loc>
  <xhtml:link 
     rel="alternate" 
     hreflang="fr" 
     href="https://www.example.fr/page1" />
</url>

<!-- Sitemap for example.fr -->
<url>
  <loc>https://www.example.fr/page1</loc>
  <xhtml:link 
     rel="alternate" 
     hreflang="en" 
     href="https://www.example.com/page1" />
</url>
```

Locale Switcher

Locale Map

FR -> `domain.fr`

EN -> `domain.en`

Other

Auto language detection and routing?

No, because domain already is locale-specific and will have locale-specific SEO.&#x20;

Cookie to handle preferred locale?&#x20;

## SEO Notes

<https://www.propellic.com/blog/how-to-choose-between-cctld-and-subfolders-for-international-seo>

[https://www.web.com/blog/what-is-cctld](https://www.web.com/blog/what-is-cctld/?utm_source=chatgpt.com)

<https://www.searchenginejournal.com/google-hints-lowering-seo-value-of-country-code-top-level-domains/523183>

<https://www.orbitmedia.com/blog/country-specific-domain-name>

<https://www.namecheap.com/blog/how-country-specific-domains-help-with-local-seo>

## Technical Notes&#x20;

* Github repo: `/sygnaltech/hf-loc-domains` &#x20;

NOT established as an HF2 micro-service, this worker currently runs independently.&#x20;


# Hyperflow LLMS

Support LLMS with llms.txt and markdown generation

* Support LLMS with llms.txt and markdown generation
* Automate update of all pages and CMS content on the site
* LLMS.TXT
  * Allow customization;
    * Auto-generated page within Webflow, using collection lists, H1's etc. &#x20;
      * e.g. `/data/llms`&#x20;
    * Static exact page source ( uploaded .txt?  HTML Embed? )&#x20;
    * Other&#x20;
* Page MD. Generate a markdown extract of every page&#x20;
  * Fully automatic
  * Accessible at e.g. `/about.md` or e.g. `/index.md` for default pages.&#x20;

## Use cases

* Improve "AI SEO" by presenting your data in a readily consumable format&#x20;
* For content-heavy public sites, improve utility of your site content by allowing users to share the `llms.txt` URL directly to an MCP server or LLM and query it.&#x20;
  * LLMS-FULL.TXT is best here, but has some challenges in the page build.&#x20;
* AI chatbots. One of the more complex challenges with AI chatbots is extracting your data and keeping it current.  Hyperflow LLMS can create a full extract of your site, ready-made for chatbot LLMs to update their content with.&#x20;

Some of my sites are very content-oriented, and I'm seeing articles I've written referenced in chatgpt responses. It feels like this is at least one direction SEO is headed?

There are three specific use cases where LLMS.TXT could theoretically benefit me;

1\. SEO / LLMO / AIO, or whatever you want to call it- the improved absorption of specific website content and backlinks to it from LLMs. Whether it's video courses, tour products, tools & solutions, consulting services...

2\. Heavy docs. In some cases the sites exist to inform, and an LLM can improve that, if it can efficiently digest the site. Literally hand it the URL to the llms.txt file and ask questions.

3\. Internal support. Some companies have huge support repositories and services directories. The support / sales team might use LLMs to look up key information, and this makes their own website content very accessible. I think website-integrated AI chatbots will begin using it to keep current as the site content is updated. New prices, new products, special offers, company news...

<https://smithery.ai/server/@thedaviddias/mcp-llms-txt-explorer>

## Decisions

Automatically convert LLMS.TXT links to the .MD version?&#x20;

## Creating Your LLMS Page

`/data/llms`&#x20;

### Headings

### Lists&#x20;

Use collection lists

> Use multiple ranges Collection Lists if you have more than 100 items.&#x20;

Inside of the collection list, you can use a custom element of `<li>` to generate markdown lists.&#x20;

Links ar best.&#x20;

## Links

Hyperflow automatically;&#x20;

* Converts the content to Markdown&#x20;
* Delivers the content at `/llms.txt`  on your site &#x20;
* Generates the X-Robots response header

## Technical Notes

<https://llmstxt.org/>

<https://langchain-ai.github.io/langgraph/llms-txt-overview/>

## Advanced&#x20;

* Securing LLMS.TXT- does this ever make sense?
* Supporting LLMS-FULL.TXT&#x20;
* Instructions on how to use with a model&#x20;

<https://github.com/thedaviddias/llms-txt-hub>


# Installing the Worker

Installing the worker

Edit the appropriate `wrangler.jsonc`&#x20;

```
npx wrangler deploy --config wrangler.navi.jsonc
```

? route not needed?&#x20;

|                        |   | Notes             |
| ---------------------- | - | ----------------- |
| name                   |   | e.g. hf-llms-navi |
| vars.POSTHOG\_API\_KEY |   |                   |
|                        |   |                   |

```json
	"routes": ["*llms.tournewzealand.com/*"],
	"vars": {
		"APP_NAME": "llms", 
		"UPSTREAM_ORIGIN": "https://www.tournewzealand.com",
		"LLMS_SOURCE_PATH": "/data/llms", 
		"ORIGIN": "https://www.tournewzealand.com",
		"TEST": "LLMS test data", 
		"POSTHOG_API_KEY": "phc_CfW1VAtR3ueFV3so5hxXQwb1l0RwsarirNw5M39Dz9T" // tournewzealand.com 
	},
```


# Setting up LLMS.TXT

{% hint style="success" %}
We recommend creating this as a standard Webflow page, under `/data/llms` .

* The folder and page must be published and can not be password-protected.&#x20;
* The page should be excluded from the Sitemap, as it is not needed by search engines.&#x20;
  {% endhint %}

The LLMS page is a standard Webflow page that you manage in the designer- however its goal is to specify the content that you want in your `/llms.txt` and nothing else. &#x20;

<figure><img src="/files/nLTTbdN7KSukxkFMGneq" alt=""><figcaption></figcaption></figure>

Hyperflow LLMS converts the page to Markdown, following your content structure;

| e.g. HTML            | e.g. Markdown |   |
| -------------------- | ------------- | - |
| `<h1>Heading 1</h1>` | `# Heading 1` |   |
| `<li>List item</li>` | `* List item` |   |
|                      |               |   |

## The LLMS.TXT Formal Specification&#x20;

{% hint style="info" %}
Hyperflow LLMS gives you full flexibility on the structure and content of your page, however it's important to follow the Formal Specifical for LLMS.TXT page construction.&#x20;
{% endhint %}

The `/llms.txt` file is Markdown but follows a specific format;&#x20;

<https://llmstxt.org/#:~:text=An%20H1%20with,about%20the%20file.>

* An H1 with the name of the project or site. This is the only required section
* A blockquote with a short summary of the project, containing key information necessary for understanding the rest of the file
* Zero or more markdown sections (e.g. paragraphs, lists, etc) of any type except headings, containing more detailed information about the project and how to interpret the provided files
* Zero or more markdown sections delimited by H2 headers, containing “file lists” of URLs where further detail is available
  * Each “file list” is a markdown list, containing a required markdown hyperlink `[name](url)`, then optionally a `:` and notes about the file.  &#x20;

Examples;

<https://developers.cloudflare.com/llms.txt>

<https://docs.anthropic.com/llms.txt>

<https://docs.perplexity.ai/llms.txt>

## Key Points

* Links should be suffixed with `.md` extension.&#x20;

## Best Practices&#x20;

*No visual styling or artwork are needed, and should be avoided.*&#x20;

For designer convenience, add this `<style>` block on your LLMS page for the best designer experience.&#x20;

```html
<style>
a { display: inline }
</style>
```

### Headings

Use Webflow's Heading elements, and arrange them in the correct hierarchical order;&#x20;

e.g.

```
H1 Fuzzy wuzzy was a bear
H2 Chapter 1
H3 In the beginning
H2 Chapter 2
```

### Lists&#x20;

{% hint style="success" %}
You can use regular Webflow List and List Item elements, however custom elements are more suitable for use in CMS-driven lists.&#x20;
{% endhint %}

We recommend an arrangement like this;&#x20;

<figure><img src="/files/M21P2f7C1KkBpr5ZFu5w" alt=""><figcaption></figcaption></figure>

Key points;

1. Custom `<ul>` or `<ol>` element&#x20;
2. Inside of this, place your collection list if you are generating the list from the CMS
3. Custom `<li>` element&#x20;
4. Webflow Link element&#x20;
   1. The link can be bound to a CMS link field&#x20;
   2. The text should be bound to the text you want directly represented by the link&#x20;
5. Custom `<span>` , containing
6. Custom `<span>` with literal `:` ( colon-space ) text sequence&#x20;
7. Custom `<span>` element&#x20;
   1. Text is a brief description of the link content&#x20;

Or if you want more control over the formatting, you can use Embeds.&#x20;

<figure><img src="/files/mCHszgdnlaoORipX0Ni9" alt=""><figcaption></figcaption></figure>

### Tables

Use an Embed element, with **HTML Table** content in it.&#x20;

Use cases;

* Hours of operation&#x20;
* A list of branch locations and addresses&#x20;
* Products, SKUs, Inventory and Pricing &#x20;

{% hint style="success" %}
You can also create your tables using a mix of custom elements and collection lists.&#x20;
{% endhint %}

```html
<table>
  <thead>
    <tr>
      <th>Header 1</th>
      <th>Header 2</th>
      <th>Header 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Row 1, Col 1</td>
      <td>Row 1, Col 2</td>
      <td>Row 1, Col 3</td>
    </tr>
    <tr>
      <td>Row 2, Col 1</td>
      <td>Row 2, Col 2</td>
      <td>Row 2, Col 3</td>
    </tr>
  </tbody>
</table>
```

Generates the following markdown; &#x20;

```markdown
|Header 1|Header 2|Header 3|
|---|---|---|
|Row 1, Col 1|Row 1, Col 2|Row 1, Col 3|
|Row 2, Col 1|Row 2, Col 2|Row 2, Col 3|
```

{% hint style="warning" %}
`<tfoot>` is not supported by the markdown converter. &#x20;
{% endhint %}

## Technical Notes

In `llms.txt`,&#x20;

Relative links will be converted to absolute links, using the same path.&#x20;

All links within the site will be suffixed with `.md` &#x20;

This is automatically handled by Hyperflow LLMS.&#x20;

## Designer CSS&#x20;

{% hint style="success" %}
**OPTIONAL.** Copy and paste this into an EMBED in your Webflow LLMS page. \
This will make your LLMS.TXT page consistent and readable with minimal site styling interference.&#x20;
{% endhint %}

```html
<style>
  /* RESET - Normalize spacing and inheritance */
  *, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }

  html, body {
    height: 100%;
    font-family: system-ui, sans-serif;
    font-size: 16px;
    line-height: 1.6;
    background: #fff;
    color: #222;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }

  /* Clear Webflow-specific defaults */
  body, h1, h2, h3, h4, h5, h6, p, ul, ol, li, a, blockquote, pre, code, table, th, td {
    all: unset;
    display: revert;
  }

  /* Typography container */
  body {
    padding: 2rem;
    max-width: 720px;
    margin: auto;
  }

  /* Headings */
  h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    line-height: 1.25;
    margin-top: 2em;
    margin-bottom: 0.5em;
  }
  h1 { font-size: 2rem; }
  h2 { font-size: 1.75rem; }
  h3 { font-size: 1.5rem; }
  h4 { font-size: 1.25rem; }
  h5 { font-size: 1.1rem; }
  h6 { font-size: 1rem; }

  /* Paragraphs */
  p {
    margin-bottom: 1rem;
  }

  /* Lists */
  ul, ol {
    padding-left: 2rem;
    margin-bottom: 1rem;
  }
  li {
    margin-bottom: 0.5rem;
  }

  /* Links */
  a {
    color: #0366d6;
    text-decoration: underline;
  }
  a:hover {
    text-decoration: none;
  }

  /* Inline code */
  code {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    background: #f6f8fa;
    padding: 0.2em 0.4em;
    border-radius: 4px;
    font-size: 0.95em;
  }

  /* Code blocks */
  pre {
    background: #f6f8fa;
    padding: 1em;
    border-radius: 6px;
    overflow-x: auto;
    margin-bottom: 1.5rem;
  }
  pre code {
    background: none;
    padding: 0;
  }

  /* Blockquotes */
  blockquote {
    border-left: 4px solid #ccc;
    padding-left: 1em;
    color: #555;
    margin: 1rem 0;
    font-style: italic;
    font-size: 1em;
    line-height: inherit;
  }

  /* Tables */
  table {
    border-collapse: collapse;
    width: 100%;
    margin-bottom: 1.5rem;
  }
  th, td {
    border: 1px solid #ddd;
    padding: 0.5em 1em;
    text-align: left;
  }
  thead {
    background: #f0f0f0;
    font-weight: 600;
  }

  /* Horizontal rule */
  hr {
    border: none;
    border-top: 1px solid #ccc;
    margin: 2rem 0;
  }
</style>
```

## Future&#x20;

Exclude conditionally hidden content&#x20;


# Setting up Markdown Pages

{% hint style="success" %}
A key reason for the LLMS.TXT standard is to remove unnecesary markup and content from the website, so that it does not consume huge amounts of tokens in the LLM's context window.&#x20;
{% endhint %}

To this end, we want to identify key content on our pages.&#x20;

## Future

{% hint style="danger" %}
**These customization features are not yet in production.** &#x20;

Currently, Hyperflow LLMS will convert the HTML page exactly to markdown with no special modifications, inclusions, exclusions, or controls.&#x20;
{% endhint %}

## Attributes&#x20;

Body

### hf-llms-mode = ( *page mode* )&#x20;

{% hint style="danger" %}
Reserved for future use.&#x20;
{% endhint %}

Place this attribute on the `<body>` element, the topmost element in the designer.&#x20;

Specify one of these page processing modes;&#x20;

* ~~`all` ( default ), Parse the entire page into markdown~~&#x20;
* `include` - will only include content on the page which is marked for inclusion ( see below ).&#x20;
* `exclude` - will include all content on the page except those sections which are specifically marked for exclusion.&#x20;

{% hint style="info" %}
`ignore`  is handled the same as `exclude`
{% endhint %}

### hf-llms = ( *element mode* )&#x20;

Place on any element in the page.  That element and it contents will be handled according to the page mode and element mode.  &#x20;

|           |                                               |   |
| --------- | --------------------------------------------- | - |
| `exclude` | Excludes the tagged element in MD generation. |   |
|           |                                               |   |
|           |                                               |   |

* `exclude` - Excludes the tagged element in MD generation.&#x20;

Future;&#x20;

* `include` - Includes the tagged element in MD generation ( when the mode is exclude )&#x20;

### hf-llms-frontmatter = ( frontmatter mode )&#x20;

{% hint style="info" %}
Reserved for future use.&#x20;
{% endhint %}

Place on the body element.&#x20;

* `include` ( default ) includes Frontmatter&#x20;
* `exclude` does not generate Frontmatter&#x20;

#### Future&#x20;

Custom to generate cvustom frontmatter from an Embed?&#x20;

| hf-llms-mode | hf-llms = exclude                       | hf-llms = include                       |
| ------------ | --------------------------------------- | --------------------------------------- |
| all          | Ignored                                 | Ignored                                 |
| include      | Excludes this element and its children. | Ignored                                 |
| exclude      | Ignored                                 | Includes this element and its children. |

## Technical Notes

### Frontmatter

Hyperflow LLMS includes Frontmatter on each of the auto-generated Markdown Pages&#x20;

```
---
Page title
Date published
Public URL
---
```


# Hyperflow LLMS API

`/.hf/app/llms`&#x20;

`/.hf/app/llms/version`&#x20;

## Test

`/.hf/api/llms/test`

`/.hf/llms/version`&#x20;


# Analytics

## Tracking Approach(es)&#x20;

### Published Crawler IP ranges&#x20;

<https://simon-thompson.me/p/tracking-published-crawler-ip-ranges>&#x20;

## Posthog

### LLMS.TXT and MD traffic&#x20;

Sygnal uses posthog for as our primary Webflow website site logs.&#x20;

Hyperflow LLMS offers direct Posthog API integration to record traffic to&#x20;

* `/llms.txt`&#x20;
* The per-page `*.md` markdown files&#x20;

### Inbound ChatGPT User traffic&#x20;

Tracking Traffic from AI Tools in GA4&#x20;

<https://kpplaybook.com/resources/how-to-report-on-traffic-from-ai-tools-in-ga4/>


# Future

## Hyperflow LLMS

* Reverse proxy all pages including standard request pages&#x20;
* Classify origin by CIDR IP range&#x20;
  * Update regularly via cron&#x20;
    * <https://raw.githubusercontent.com/searchtheoryio/ips/refs/heads/main/dist/ips.json>&#x20;
    * Yes they do change&#x20;
      * <https://www.linkedin.com/posts/ryansiddle_woah-openai-just-added-512-new-ip-addresses-activity-7323590222904995843-UIs3/>
* Must log to PH directly to pass the data properly&#x20;

## Notes&#x20;

<https://simon-thompson.me/p/tracking-published-crawler-ip-ranges>&#x20;

<https://help.oncrawl.com/en/articles/11872799-how-to-detect-and-analyze-ai-and-llms-bots-hits-using-log-monitoring>


# ChatGPT ( OpenAI )

## Traffic&#x20;

OpenAI has three distinct bots-&#x20;

<table><thead><tr><th width="240.33331298828125">Bot</th><th>UserAgent</th><th>Tracking</th></tr></thead><tbody><tr><td><strong>GPTBot</strong><br>Used for crawling content that may be used in training OpenAI's generative AI foundation models.</td><td>Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.1; +https://openai.com/gptbot</td><td>Current CIDRs-<br><a href="https://openai.com/gptbot.json">https://openai.com/gptbot.json</a> <br><br>User agent may be a suitable backup, but is easily spoofed.</td></tr><tr><td><strong>OAI-SearchBot</strong><br>Used for search functionality in ChatGPT's search features. It is not used to crawl content for training AI models. </td><td>Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot </td><td>Current CIDRs-<br><a href="https://openai.com/searchbot.json">https://openai.com/searchbot.json</a><br><br>User agent may be a suitable backup, but is easily spoofed.</td></tr><tr><td><strong>ChatGPT-User</strong><br>Used when users ask ChatGPT or a Custom GPT to visit a web page. It's not used for automatic crawling or AI training.</td><td>Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot</td><td>Current CIDRs-<br><a href="https://openai.com/chatgpt-user.json">https://openai.com/chatgpt-user.json</a><br><br>User agent may be a suitable backup, but is easily spoofed.</td></tr></tbody></table>

It also has direct user traffic when a user clicks a link from ChatGPT.&#x20;

```
?utm_source=chatgpt.com
```

## Tracking&#x20;

Server-side&#x20;

1. Check signature to verify&#x20;

Client-side&#x20;

1. Prefer CIDRs ( keep list updated )&#x20;
2.

OpenAI publishes a list of ChatGPT User CIDRs here-&#x20;

<https://openai.com/chatgpt-user.json>

These indicate the IP ranges&#x20;

<http://openai.com/searchbot.json>

<https://openai.com/gptbot.json>

**What the “ChatGPT-User” CIDRs represent**

* They are **egress IPs used by ChatGPT** when it makes **outbound HTTP(S) requests to the public internet on a user’s behalf** (e.g., the ChatGPT agent or a GPT fetching a page/API). ([OpenAI Help Center](https://help.openai.com/en/articles/11845367-chatgpt-agent-allowlisting))
* Triggers include:
  * **Agent/automation visits to websites** while completing tasks. ([OpenAI Help Center](https://help.openai.com/en/articles/11845367-chatgpt-agent-allowlisting))
  * **GPT Actions** calling **third-party APIs** from ChatGPT. ([OpenAI Help Center](https://help.openai.com/en/articles/9442513-gpt-actions-domain-settings-chatgpt-enterprise))
  * **Link retrieval/visits generated in ChatGPT** (when ChatGPT provides links or fetches online sources for a reply). ([OpenAI Help Center](https://help.openai.com/en/articles/10984597-chatgpt-generated-links))

**What they are not**

* They are **not the training crawler** (“GPTBot”) IPs. GPTBot is a separate crawler used for web data collection and is documented independently. ([OpenAI](https://platform.openai.com/docs/gptbot?utm_source=chatgpt.com))

**How to positively identify ChatGPT traffic (recommended over IP matching alone)**

* Validate the **HTTP Message Signatures** ChatGPT adds to outbound requests (`Signature`, `Signature-Input`, and `Signature-Agent: "https://chatgpt.com"`). This cryptographically proves a request came from ChatGPT. ([OpenAI Help Center](https://help.openai.com/en/articles/11845367-chatgpt-agent-allowlisting))
* Major CDNs also expose verified detections (e.g., **Vercel Verified Bots** and Cloudflare’s bot directory entry for ChatGPT agent), which you can allowlist. ([Vercel](https://vercel.com/docs/botid/verified-bots?utm_source=chatgpt.com))

**Heads-up on the “ChatGPT-User” label**

* Many site owners also see the **“ChatGPT-User” user-agent token** associated with these requests; it’s widely documented by third-party bot directories. Use signatures for assurance, since UAs can be spoofed. ([Dark Visitors](https://darkvisitors.com/agents/chatgpt-user?utm_source=chatgpt.com))

**Reference to the CIDR list itself**

* OpenAI publishes the “ChatGPT-User” IP ranges as a JSON feed (`/chatgpt-user.json`). Use that feed for the current list, but rely on signature verification when possible. ([community.openai.com](https://community.openai.com/t/ip-range-for-bot-detection-allow-list/1287217?utm_source=chatgpt.com))

## Future

{% hint style="warning" %}
Consider using Hyperflow LLMS to receive and verify inbound request headers, and pass that information through to Posthog, rather than the injected script approach.&#x20;
{% endhint %}

PostHog transforms (Hog) run on **event payloads**, not raw HTTP requests, and they **don’t have access to inbound request headers** (e.g. `Signature`, `Signature-Input`). They also can’t make outbound fetches to validate signatures. Therefore you **can’t verify HTTP Message Signatures inside a PostHog transform**.

Do signature verification at your edge/app (e.g., Cloudflare Worker, server, CDN function). When a request is verified as ChatGPT, attach a flag into the PostHog event you emit (or set a cookie/param your client capture reads). Then let Hog classify it first.

Minimal Hog change (add this to the top of your classifier):

```hog
// 0) Prefer cryptographic proof set upstream
if (event.properties['chatgpt_signature_verified'] = true) {
    event.properties['ai_traffic'] := true
    event.properties['ai_traffic_platform'] := 'chatgpt'
    event.properties['ai_traffic_type'] := 'chatgpt_user'
    event.properties['ai_traffic_identifier'] := 'signature'
    return event
}
```

Pipeline summary:

1. **Edge/server**: verify ChatGPT HTTP message signature on the incoming request; if valid, include `chatgpt_signature_verified=true` when you send/capture the PostHog event (or expose it to the client so the JS capture can attach it).
2. **Hog**: fall back to your other signals:
   * CIDR match → `ai_traffic_type='chatgpt_user'`, `ai_traffic_identifier='ip'`
   * GPTBot UA/IP → `ai_traffic_type='gptbot'`, identifier `ua` or `ip`
   * Referrer/UA (“chatgpt.com”, “chat.openai.com”, “ChatGPT”) → `ai_traffic_type='chatgpt_click'`, identifier `referrer` or `ua`

This yields cryptographic certainty when available, with IP/UA/referrer as explicit fallbacks.


# Posthog Tracking Code

Event transformer

## Unified Transformer&#x20;

Identifies OpenAI ChatGPT traffic only, in all 3 forms, using CIDR matching.&#x20;

{% hint style="warning" %}
**Currently in testing.** \
SYGNAL.COM, since 13-Sep-2025 18:30 NZT.&#x20;
{% endhint %}

```
// Hog transformation: tag events whose IPv4 is in ChatGPT CIDRs.
// Always returns the event (pass-through if no match).

fun ipToInt(ip) {
    if (ip = null) { return null }
    // Skip IPv6
    if (match(ip, ':')) { return null }

    let parts := splitByString('.', ip)
    if (length(parts) != 4) { return null }

    let a := toInt(parts[1])
    let b := toInt(parts[2])
    let c := toInt(parts[3])
    let d := toInt(parts[4])

    if (a < 0 or a > 255 or b < 0 or b > 255 or c < 0 or c > 255 or d < 0 or d > 255) { return null }
    return a*16777216 + b*65536 + c*256 + d
}

fun pow2(n) {
    let r := 1
    let i := 0
    while (i < n) {
        r := r * 2
        i := i + 1
    }
    return r
}

fun cidrToRange(cidr) {
    let p := splitByString('/', cidr)
    if (length(p) != 2) { return null }
    let base := p[1]
    let bits := toInt(p[2])
    if (bits < 0 or bits > 32) { return null }

    let baseInt := ipToInt(base)
    if (baseInt = null) { return null }

    let hostBits := 32 - bits
    let size := pow2(hostBits)
    let start := toInt(baseInt / size) * size
    let end := start + size - 1
    return (start, end)
}

// ChatGPT-User CIDR source (2025-09-11T23:02:11.854419)
let CHATGPT_USER_CIDRS := [
'23.98.142.176/28','23.102.140.144/28','13.65.138.112/28','23.98.179.16/28','13.65.138.96/28',
'172.183.222.128/28','20.102.212.144/28','40.116.73.208/28','172.183.143.224/28','52.190.190.16/28',
'13.83.237.176/28','51.8.155.64/28','74.249.86.176/28','51.8.155.48/28','20.55.229.144/28',
'135.237.131.208/28','135.237.133.48/28','51.8.155.112/28','135.237.133.112/28','52.159.249.96/28',
'52.190.137.16/28','52.255.111.112/28','40.84.181.32/28','172.178.141.112/28','52.190.142.64/28',
'172.178.140.144/28','52.190.137.144/28','172.178.141.128/28','57.154.187.32/28','4.196.118.112/28',
'20.193.50.32/28','20.215.188.192/28','20.215.214.16/28','4.197.22.112/28','4.197.115.112/28',
'172.213.21.16/28','172.213.11.144/28','172.213.12.112/28','172.213.21.144/28','20.90.7.144/28',
'57.154.175.0/28','57.154.174.112/28','52.236.94.144/28','137.135.191.176/28','23.98.186.192/28',
'23.98.186.96/28','23.98.186.176/28','23.98.186.64/28','68.221.67.192/28','68.221.67.160/28',
'13.83.167.128/28','20.228.106.176/28','52.159.227.32/28','68.220.57.64/28','172.213.21.112/28',
'68.221.67.224/28','68.221.75.16/28','20.97.189.96/28','52.252.113.240/28','52.230.163.32/28',
'172.212.159.64/28','52.255.111.80/28','52.255.111.0/28','4.151.241.240/28','52.255.111.32/28',
'52.255.111.48/28','52.255.111.16/28','52.230.164.176/28','52.176.139.176/28','52.173.234.16/28',
'4.151.71.176/28','4.151.119.48/28','52.255.109.112/28','52.255.109.80/28','20.161.75.208/28',
'68.154.28.96/28','52.255.109.128/28','52.255.109.96/28','52.255.109.144/28','52.173.234.80/28',
'132.196.82.48/28','20.249.63.208/28','20.63.221.64/28','13.76.116.80/28','20.235.87.224/28',
'4.205.128.176/28','52.225.75.208/28','52.190.139.48/28','68.221.67.240/28','40.75.14.224/28',
'135.119.134.192/28','51.8.155.80/28','135.119.134.128/28','52.173.219.112/28','52.242.132.224/28',
'52.173.219.96/28','52.242.132.240/28','74.7.36.64/28','74.7.36.96/28','74.7.35.48/28',
'74.7.35.112/28','74.7.36.80/28','52.156.77.144/28','52.148.129.32/28','20.117.22.224/28',
'20.235.75.208/28','172.204.16.64/28','4.196.198.80/28','20.194.157.176/28','23.102.141.32/28',
'52.173.235.80/28','52.173.123.0/28','40.84.221.208/28','104.210.139.224/28','20.0.53.96/28',
'52.154.22.48/28','52.242.245.208/28','191.235.66.16/28','191.233.196.112/28','191.233.194.32/28',
'23.97.109.224/28','138.91.46.96/28','13.76.32.208/28','52.187.246.128/28','13.70.107.160/28',
'138.91.30.48/28','20.210.154.128/28','20.194.1.0/28','20.194.0.208/28','20.77.178.240/28',
'4.234.83.96/28','40.84.221.224/28','104.210.139.192/28','191.239.245.16/28','191.234.167.128/28',
'191.235.99.80/28','191.235.98.144/28','68.218.30.112/28','4.197.19.176/28','20.27.94.128/28',
'20.210.174.208/28','20.204.24.240/28','20.198.67.96/28'
]

// GPTBot (2025-05-22T11:51:00)
let GPTBOT_CIDRS := [
'52.230.152.0/24','20.171.206.0/24','20.171.207.0/24','4.227.36.0/25',
'20.125.66.80/28','172.182.204.0/24','172.182.214.0/24','172.182.215.0/24'
]

// SearchBot (2025-06-11T12:00:00)
let SEARCHBOT_CIDRS := [
'20.42.10.176/28','172.203.190.128/28','104.210.140.128/28','51.8.102.0/24','135.234.64.0/24',
'172.182.195.48/28','20.25.151.224/28','20.171.53.224/28','20.169.6.224/28','172.182.193.80/28',
'172.182.193.224/28','172.182.194.32/28','172.182.194.144/28','172.182.213.192/28','172.182.209.208/28',
'172.182.224.0/28','172.182.211.192/28','20.169.7.48/28','20.168.18.32/28','20.171.123.64/28','20.14.99.96/28'
]

// Precompute numeric ranges
let CHATGPT_USER_RANGES := []
for (let i := 1; i <= length(CHATGPT_USER_CIDRS); i := i + 1) {
    let r := cidrToRange(CHATGPT_USER_CIDRS[i])
    if (r != null) {
        CHATGPT_USER_RANGES := arrayPushBack(CHATGPT_USER_RANGES, r)
    }
}

let GPTBOT_RANGES := []
for (let i := 1; i <= length(GPTBOT_CIDRS); i := i + 1) {
    let r := cidrToRange(GPTBOT_CIDRS[i])
    if (r != null) {
        GPTBOT_RANGES := arrayPushBack(GPTBOT_RANGES, r)
    }
}

let SEARCHBOT_RANGES := []
for (let i := 1; i <= length(SEARCHBOT_CIDRS); i := i + 1) {
    let r := cidrToRange(SEARCHBOT_CIDRS[i])
    if (r != null) {
        SEARCHBOT_RANGES := arrayPushBack(SEARCHBOT_RANGES, r)
    }
}

// Copy event to make it mutable
let returnEvent := event
returnEvent.properties := returnEvent.properties ?? {}

// Prefer upstream cryptographic proof if you set it at your edge
if (returnEvent.properties['chatgpt_signature_verified'] = true) {
    returnEvent.properties['ai_traffic'] := true
    returnEvent.properties['ai_traffic_platform'] := 'chatgpt'
    returnEvent.properties['ai_traffic_type'] := 'chatgpt_user'
    returnEvent.properties['ai_traffic_identifier'] := 'signature'
    return returnEvent
}

let ip := returnEvent.properties['$ip'] ?? returnEvent.properties['ip'] ?? returnEvent['$ip']
let ipInt := ipToInt(ip)

if (ipInt != null) {
    // Check GPTBot first
    for (let i := 1; i <= length(GPTBOT_RANGES); i := i + 1) {
        if (ipInt >= GPTBOT_RANGES[i].1 and ipInt <= GPTBOT_RANGES[i].2) {
            returnEvent.properties['ai_traffic'] := true
            returnEvent.properties['ai_traffic_platform'] := 'chatgpt'
            returnEvent.properties['ai_traffic_type'] := 'gptbot'
            returnEvent.properties['ai_traffic_identifier'] := 'ip'
            return returnEvent
        }
    }
    
    // Check SearchBot
    for (let i := 1; i <= length(SEARCHBOT_RANGES); i := i + 1) {
        if (ipInt >= SEARCHBOT_RANGES[i].1 and ipInt <= SEARCHBOT_RANGES[i].2) {
            returnEvent.properties['ai_traffic'] := true
            returnEvent.properties['ai_traffic_platform'] := 'chatgpt'
            returnEvent.properties['ai_traffic_type'] := 'searchbot'
            returnEvent.properties['ai_traffic_identifier'] := 'ip'
            return returnEvent
        }
    }
    
    // Check ChatGPT User
    for (let i := 1; i <= length(CHATGPT_USER_RANGES); i := i + 1) {
        if (ipInt >= CHATGPT_USER_RANGES[i].1 and ipInt <= CHATGPT_USER_RANGES[i].2) {
            returnEvent.properties['ai_traffic'] := true
            returnEvent.properties['ai_traffic_platform'] := 'chatgpt'
            returnEvent.properties['ai_traffic_type'] := 'chatgpt_user' 
            returnEvent.properties['ai_traffic_identifier'] := 'ip'
            return returnEvent
        }
    }
}

// Set ai_traffic = false if no match
returnEvent.properties['ai_traffic'] := false

// Always pass through
return returnEvent
```


# Future

Enhanced tracking within Hyperflow LLMS

Edge notes:

* **Gemini/Google**: implement reverse-DNS verification (PTR → `*.googlebot.com|*.google.com|*.googleusercontent.com` and forward-resolve back) in your Cloudflare Worker or server; then set `google_verified_crawler=true` on the event. [Google for Developers+1](https://developers.google.com/search/docs/crawling-indexing/verifying-googlebot?utm_source=chatgpt.com)
* **Perplexity**: periodically refresh the two JSON lists; IP-only may still miss undeclared crawlers per Cloudflare’s report. [Perplexity+2The Cloudflare Blog+2](https://docs.perplexity.ai/guides/bots)
* **Claude**: only the **agent/tool egress** IPs are officially published; there is no official CIDR feed for **ClaudeBot**. [Anthropic+1](https://docs.anthropic.com/en/api/ip-addresses)


# Perplexity

**Perplexity**: Use their official JSON feeds for CIDRs: `perplexitybot.json` (crawler) and `perplexity-user.json` (user-initiated fetcher). Paste those CIDRs into your transform and tag accordingly. Note: Cloudflare reports “stealth” crawling from undeclared IPs, so IP-only matching can miss traffic. [Perplexity+2The Cloudflare Blog+2](https://docs.perplexity.ai/guides/bots)

{% embed url="<https://docs.perplexity.ai/guides/bots>" %}

* PerplexityBot
* Perplexity-User

<table><thead><tr><th width="166">User Agent</th><th>Description</th></tr></thead><tbody><tr><td>PerplexityBot</td><td><code>PerplexityBot</code> is designed to surface and link websites in search results on Perplexity. It is not used to crawl content for AI foundation models. To ensure your site appears in search results, we recommend allowing <code>PerplexityBot</code> in your site’s <code>robots.txt</code> file and permitting requests from our published IP ranges listed below.<br><br>Full user-agent string: <code>Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)</code><br><br>Published IP addresses: <a href="https://www.perplexity.com/perplexitybot.json">https://www.perplexity.com/perplexitybot.json</a></td></tr><tr><td>Perplexity‑User</td><td><code>Perplexity-User</code> supports user actions within Perplexity. When users ask Perplexity a question, it might visit a web page to help provide an accurate answer and include a link to the page in its response. <code>Perplexity-User</code> controls which sites these user requests can access. It is not used for web crawling or to collect content for training AI foundation models.<br><br>Full user-agent string: <code>Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)</code><br><br>Published IP addresses: <a href="https://www.perplexity.com/perplexity-user.json">https://www.perplexity.com/perplexity-user.json</a><br><br>Since a user requested the fetch, this fetcher generally ignores robots.txt rules.</td></tr></tbody></table>

## Notes

<https://www.xseek.io/docs/perplexity-user-agents>&#x20;


# Deepseek

## Notes

<https://www.xseek.io/docs/deepseek-user-agents>&#x20;


# Llama

## Notes&#x20;

<https://www.xseek.io/docs/llama-user-agents>&#x20;


# Bing ( Microsoft )

## Notes&#x20;

<https://www.xseek.io/docs/bing-ai-user-agents>


# Claude ( Anthropic )

**Claude (Anthropic)**: Use Anthropic’s **outbound IPs** for agent/tool egress (convert to /32). There’s **no official CIDR list** for the **ClaudeBot** crawler; if you need to tag it, you’ll have to rely on UA or third-party lists (less reliable).

<https://docs.anthropic.com/en/api/ip-addresses>


# Gemini ( Google )

**Google Gemini**: Google doesn’t publish CIDRs for crawlers. The official method is **reverse-DNS verification** (IP ⇄ `googlebot.com`/`google.com`/`googleusercontent.com`). Do that at your edge and pass a boolean into PostHog (e.g., `google_verified_crawler=true`). IP-only in PostHog isn’t feasible.

[https://developers.google.com/search/docs/crawling-indexing/verifying-googlebot](https://developers.google.com/search/docs/crawling-indexing/verifying-googlebot?utm_source=chatgpt.com)


# Future

## Improved Markdown Support

Allowing raw chunks of static markdown

```html
<script type="hf/md">
... raw markdown
</script> 
```

## Configs

Support either internal configs for upstream, or controller-driven configs&#x20;

Smart failure for unconnected RPC's at DEV&#x20;

## YAML

There is currently **no formal specification** for `llms.txt` that defines support for YAML frontmatter or structured blocks like that. However:

* LLMS crawlers like **OpenAI**, **Anthropic**, **Perplexity**, etc., **are starting to read `llms.txt`** files with simple key-value lines.
* There's growing **community consensus** around a flexible, plaintext-friendly structure that is easy to parse and human-readable.

#### ✅ Recommended Format for `llms.txt` (as of 2024–2025)

The most commonly observed structure follows simple `key: value` pairs, like:

```txt
txtCopyEditpage: https://example.com/about
source: https://example.com/about.md
license: CC-BY-4.0
llm: openai
```

You can see examples and early proposals from:

* [OpenAI’s LLM training data documentation](https://openai.com/llms)
* [GitHub repos](https://github.com/search?q=llms.txt) exploring `llms.txt` format (some maintained by AI transparency advocates)
* Discussions on Hacker News, [GitHub Issues](https://github.com/topics/llms.txt), and community forums


# Hyperflow Favicon

Responds to /favicon.ico requests with a valid ICO reponse.

Dynamically generates multi-resolution ICO favicons for Webflow sites by extracting and composing icon images from the site's homepage.&#x20;

{% hint style="warning" %}
**STATUS: TESTING** \
Currently in SEO testing on Sygnal's site.  &#x20;

<https://www.sygnal.com/favicon.ico>&#x20;
{% endhint %}

### Features&#x20;

#### Smart Icon Detection

* Automatically fetches the homepage and extracts icon links
* Supports multiple icon types:
  * `<link rel="shortcut icon">`
  * `<link rel="icon">`
  * `<link rel="apple-touch-icon">`
* Resolves relative and absolute URLs correctly

#### Multi-Format Support

* **Primary**: PNG images (most common in Webflow)
* **ICO extraction**: Can extract PNG data from existing ICO files
* **Graceful degradation**: Skips unsupported formats (GIF, JPG) that require transcoding

#### ICO Composition

* Builds valid multi-resolution ICO files from multiple PNG sources
* Embeds PNGs directly without transcoding (efficient and fast)
* Sorts icons by size for optimal browser compatibility
* Supports icons up to 256×256 pixels

#### Performance & Caching

* **Edge caching**: Returns cached ICO files instantly for repeat requests
* **7-day cache**: `Cache-Control: public, max-age=604800, immutable`
* **Upstream caching**: Caches homepage and icon fetches at Cloudflare edge
* Zero dependencies, optimized for Cloudflare Workers runtime

#### Error Handling

* Gracefully handles missing or invalid icons
* Continues processing if individual icon fetches fail
* Returns appropriate HTTP status codes (404, 502, 500)

### How It Works

1. **Request**: Browser requests `/favicon.ico` from your domain
2. **Fetch**: Worker fetches the homepage (`/`) from the same origin
3. **Parse**: Extracts icon URLs from `<link>` tags in the HTML
4. **Download**: Fetches each icon image (with edge caching)
5. **Process**: Reads PNG dimensions and validates format
6. **Compose**: Builds a multi-resolution ICO file containing all valid PNGs
7. **Cache & Serve**: Returns the ICO with aggressive caching headers

### Usage

Once deployed, the worker will automatically respond to `/favicon.ico` requests:

```
https://your-domain.com/favicon.ico
```

All other paths return a 404 response.

### Configuration

The worker requires no configuration. It automatically:

* Detects the request origin
* Fetches the homepage from the same origin
* Extracts and processes icons
* Caches results at the edge

### Technical Details

#### Icon Extraction

Uses regex-based HTML parsing to find icon `<link>` tags:

```regex
/<link[^>]*rel=["'](?:shortcut\s+icon|icon|apple-touch-icon)["'][^>]*>/gi
```

#### PNG Format Detection

Validates PNG files by checking the 8-byte signature:

```
89 50 4E 47 0D 0A 1A 0A
```

#### ICO File Structure

Generates valid ICO files with:

* ICONDIR header (6 bytes)
* ICONDIRENTRY for each image (16 bytes each)
* PNG image data (embedded without transcoding)

#### Size Handling

* Icons ≥256px are encoded as `0` in ICO directory (per ICO spec)
* Smaller icons use their actual dimensions
* Multiple resolutions are sorted smallest to largest

### Limitations

* **PNG focus**: Webflow typically uses PNG icons. GIF and JPG formats are skipped unless they can be extracted from ICO containers
* **Image transcoding**: No built-in image format conversion (keeps worker lightweight)
* **Same-origin**: Fetches icons from the same domain as the request

### Development

#### Local Testing

```bash
npm run dev
```

Visit `http://localhost:8787/favicon.ico`

#### Type Generation

```bash
npm run cf-typegen
```

#### Deployment

```bash
npm run deploy
```

### Troubleshooting

#### "No icons found" error

* Ensure your Webflow site has `<link rel="icon">` or `<link rel="apple-touch-icon">` tags in the homepage HTML
* Check that the icon URLs are accessible

#### "No valid PNG icons found" error

* Verify that your icons are in PNG format
* Check that icon URLs return valid PNG data
* Ensure icons have valid PNG headers (signature + IHDR chunk)

#### Cache issues

* Edge cache lasts 7 days
* To force refresh, clear Cloudflare cache or wait for TTL expiration
* During development, use `wrangler dev` which bypasses edge cache

## Future&#x20;

* Interpolate
  * 48x48 size in ICO&#x20;
  * 16x16 size in ICO
* SVG icon support ?&#x20;
* Desktop PNG favicon ?&#x20;
* Android chrome favicon not set  \
  Chrome selects the 192x192 icon if it is available and the 128x128 icon if it is not.
* Rel shortcut icon&#x20;

  ```
  <link rel="shortcut icon" href="/path/to/favicon">
  ```
* Consider ref&#x20;

  ```
  <link rel="icon" type="image/x-icon" href="url_to_my_favicon" /> 
  ```

<https://realfavicongenerator.net/favicon-checker>

### PWA & Web manifest&#x20;

<https://web.dev/articles/add-manifest>

|                                      |                           |                   |
| ------------------------------------ | ------------------------- | ----------------- |
| \<link> shortcut icon                | Webflow, 32x32            |                   |
| \<link> icon                         |                           |                   |
| \<link> apple-touch-icon             | Webflow, 256x256          |                   |
| \<link> apple-touch-icon-precomposed |                           |                   |
| /favicon.ico                         |                           | Hyperflow Favicon |
| /manifest.json                       | Webflow internal, not PWA |                   |

<table><thead><tr><th width="109"></th><th></th><th></th></tr></thead><tbody><tr><td>16x16</td><td></td><td></td></tr><tr><td>24x24</td><td></td><td></td></tr><tr><td>32x32</td><td>Use Webflow's uploaded icon, PNG preferred </td><td></td></tr><tr><td>48x48</td><td></td><td></td></tr><tr><td>64x64</td><td></td><td></td></tr><tr><td>128x128</td><td></td><td>Chrome selects the 192x192 icon if it is available and the 128x128 icon if it is not.</td></tr><tr><td>192x192</td><td></td><td>Chrome selects the 192x192 icon if it is available and the 128x128 icon if it is not.</td></tr><tr><td>256x256</td><td>Use Webflow's uploaded icon, PNG preferred </td><td></td></tr></tbody></table>


# Hyperflow CMS Preview

An advanced staging setup for businesses that supports Staged Changes.

Webflow's has recently released a CMS Item publishing feature which allows you manage CMS content much more precisely;

When you make changes to a CMS item, you can;&#x20;

* Publish that item individually without republishing the entire site
* Queue that item to be published when the entire site is published&#x20;
* Save your changes as Draft Changes, which are not published until you choose to publish them.  This supports length change process and team environments much more completely.&#x20;

## The Limitation&#x20;

One of the side effects of this more robust process is that the staging process changes.  Your webflow\.io staging still works great for site publishing, but it is not part of CMS item changes.&#x20;

This means that when you edit a CMS item, it's very difficult to see those Draft Changes on staging *before* your content goes live.&#x20;

This presents a problem for;

* Teams who want to preview and test content&#x20;
* Complex sites that involve scripts and frameworks as part of the content delivery&#x20;
* Users who need to see and approve the content before it goes live- but who do not have designer access.&#x20;

## Hyperflow CMS Preview

Hyperflow CMS Preview creates a special staging version of your site, on a domain or subdomain that you choose.  It shows all of your current site content, but CMS items show the Draft Changes version which is not normally visible.&#x20;

**The experience is fantastic.  Edit content in the designer, and&#x20;*****without publishing anything*****, you can immediately switch to Hyperflow CMS Preview to see your content live.**&#x20;

{% embed url="<https://www.loom.com/share/6fff7efdb44b44ccae16f95fb0050571>" %}

{% hint style="warning" %}
Currently, CMS Preview supports **Collection Pages**, but *does not support* **Collection Lists**.  In part this is due to Webflow's API rate limits and the huge API traffic that would be required to fetch those items and build the page.&#x20;
{% endhint %}

works by displaying the Draft Changes content in your page

The underlying site can be your webflow\.io staging site, or your production site, depending on which makes sense for you.  Or, we can setup both on different subdomains, like;

## Setup

The DNS for Hyperflow CMS Preview must be on Cloudflare- however you can choose to run it separately from your main public domain.  This means your&#x20;

Sygnal will install and setup the Hyperflow CMS Preview feature&#x20;

You'll need a read-only Webflow API key that has the ability to get CMS items for this site ( no write permissions needed ).&#x20;

Sygnal will add this to your configuration.&#x20;

### Options

* Choose your subdomain or domain name for Webflow
  * E.g. preview\.mysite.com , where mysite.com is your main Webflow-hosted site&#x20;
  * Or, preview-mysite.com, a completely different domain that is unrelated to your Webflow-hosted site.&#x20;
* Configure your CMS pages with CMS content&#x20;
* `hf-cmspreview-field`&#x20;

{% hint style="success" %}
Rich text elements are automatically identified by the class w-richtext.&#x20;
{% endhint %}

{% hint style="success" %}
Webflow's empty classes are automatically added or removed to show or hide elements appropriately when they have content.&#x20;
{% endhint %}

```
<a hf-cmspreview-

```

## Supported CMS Field Types

| CMS Field Type       | Text element | Supported? |
| -------------------- | ------------ | ---------- |
| Text                 |              | YES        |
| Rich Text            |              | YES        |
| Image                |              |            |
| Component Properties |              |            |
| Video                |              |            |
| Color                |              |            |
| Boolean              |              |            |

## Advanced Features

### JSON Access&#x20;

<figure><img src="/files/6YLyolOn4QA1dVGLUjwC" alt=""><figcaption></figcaption></figure>

## Future

* Collection Lists&#x20;
*


# Hyperflow Files

Serve plain text files at any path. Designed for verification services like Apple Pay.

Features;

* Serve any static text file at any URL on your Webflow-hosted site

Use cases;

* Apple pay verification
* Google Adsense ads.txt setup&#x20;
* other verifications&#x20;

## Installation

Hyperflow Files is an independent worker, named `hf-files`.

## Usage Notes

### Define the file to serve

In the FILES KV store, add an entry to represent your file with the base domain and full file path.

e.g.;

```
mysite.com/.well-known/apple-developer-merchantid-domain-association
```

* Do not include the `https://` or `www` subdomain prefix.&#x20;
  * A subdomain can be specified if required
* Make sure to include the file extension if one is needed&#x20;
  * However all files will be served as plaintext MIME type&#x20;

As the value of the KV entry, paste in the full text content of the file

### Define your route

In your site's worker routes, add a route to the worker, e.g.;

```
*mysite.com/.well-known/apple-developer-merchantid-domain-association
```

To the `hf-files` worker.&#x20;

{% hint style="info" %}
If you have multiple files you need to configure this way, you can
{% endhint %}


# Hyperflow Notion

## Features&#x20;

* Supports Notion-to-Webflow sync from any Notion DB to any Webflow CMS Collection.&#x20;
* Allows specific field mappings&#x20;
* Solidifies mapping by pushing back the Webflow item ID into Notion&#x20;
* Auto-generates slug from name, if it is blank&#x20;

Field types;&#x20;

* Handles content to Webflow rich text HTML conversion&#x20;
* Handles cover images&#x20;
* Ref's, by slug&#x20;

## Mapping&#x20;

<table><thead><tr><th width="139.6666259765625">Notion</th><th width="191.333251953125">Webflow</th><th>Notes </th></tr></thead><tbody><tr><td>Webflow ID</td><td>id </td><td><strong>Required.</strong> Internal Webflow ID.  </td></tr><tr><td>Slug</td><td>slug </td><td>Webflow Slug. </td></tr><tr><td>_cover </td><td>( <em>any image field</em> )</td><td><strong>Optional.</strong> Stored in the specified field. </td></tr><tr><td>_content </td><td>( <em>any richtext field</em> )</td><td><strong>Optional.</strong> Converted to Webflow richtext-compatible HTML and stored in the specified field. </td></tr><tr><td>( <em>any other field</em> )</td><td>( <em>any Webflow field</em> )</td><td><strong>Optional.</strong> Converted to Webflow. </td></tr></tbody></table>

### Webflow ID&#x20;

**Required.**  In Notion, create a text field.  We recommend the name Webflow ID.  Add it to the field mapping to Webflow field \_id. &#x20;

* When blank, HF Notion knows that this is a new item, and will create it.&#x20;
  * Once created, it will update the field in Notion to complete the sync definition for future updates.&#x20;
* When populated, HF Notion knows that this is an existing item, and will update it.&#x20;

```json
    "Webflow ID": {
      "webflowField": "_id",
      "type": "text"
    }     
```

### Slug&#x20;

Represents the slug of the item.&#x20;

When the item is first created;&#x20;

* If blank, HF Notion will automatically create the slug, use it in Webflow and push it back to your Notion DB as well.&#x20;
* If set, HF Notion will use the one you've set.  Be sure it doesn't conflict with an existing slug or you may have problems.&#x20;

Updating the slug in Notion should update it in Webflow as well.&#x20;

### \_cover&#x20;

This is generated from Notion's cover image.  You can upload your own, or set one from various services for free.&#x20;

### \_content&#x20;

This is the main document in Notion and is converted to Webflow rich text.&#x20;

Converts Notion blocks to Webflow field types. &#x20;

* Paragraphs
* Headings&#x20;
* Images&#x20;
* Tables&#x20;
* Videos&#x20;

### Other Fields&#x20;

Other custom fields can be added to your Notion DB as well and mapped to&#x20;

{% hint style="info" %}
Ref fields are supported as well.  Use the Ref item's slug.&#x20;
{% endhint %}

## Future &#x20;

Individual documents, connected to Webflow pages (?)  Maybe not, due to CMS challenges&#x20;

Localization processes?  Auto-translation and push?&#x20;

Expand field types.&#x20;

## Setup&#x20;

### Notion Side&#x20;

DB Fields-&#x20;

* &#x20;Title ( intrinsic ). Maps to the Name&#x20;
* `Slug` ( text ).  Maps to the Slug.  Auto-generated by the API from the Title using a Slug-compatible formula. &#x20;
* `Webflow ID` ( text ). This will be used by HF Notion to distinguish create v update requests, and to track sync bindings.&#x20;
* Content ( HTML ).&#x20;
* Cover ( Image ).&#x20;

Create the Webhook  &#x20;

* Access. Give it the Databases you want. &#x20;

<https://www.notion.so/profile/integrations/internal/e38d8085-0347-4c40-941c-f444d31b33fd>&#x20;

### Cloudflare KV&#x20;

KV Store is `NOTION_SYNC_CONFIGS`&#x20;

```json
{
  "name": "Blog",
  "notionDatabaseId": "28e6e09372ee80e1bd3bf34b113d4673",
  "webflowCollectionId": "59d3f382f210ca00015829d5",
  "fieldMappings": {
    "Webflow ID": {
      "webflowField": "_id",
      "type": "text"
    },
    "Name": {
      "webflowField": "name",
      "type": "text"
    },
    "Slug": {
      "webflowField": "slug",
      "type": "text"
    },
    "_content": {
      "webflowField": "post-body",
      "type": "html",
      "headingAdjust": 1
    },
    "Publish Date": {
      "webflowField": "published-date",
      "type": "date"
    },
    "Updated Date": {
      "webflowField": "date-updated",
      "type": "date"
    },
    "_cover": {
      "webflowField": "thumbnail-image",
      "type": "image"
    }
  },
  "publishControl": {
    "field": "Status",
    "publishValue": "Published"
  }
}

```

e.g. <https://dash.cloudflare.com/9095ee3415dc7ee4e497da2a3c8d1992/workers/kv/namespaces/7f2efd02f52b4033b003edb88987c660>&#x20;

## Testing&#x20;

### Notion Side&#x20;

Create a test Webhook&#x20;

* Access. Give it the Databases you want.&#x20;

<https://www.notion.so/profile/integrations/internal/12765ef2-4b61-4ccc-b74a-1fb667eccd81>


# Styling

Styling Notion-generated HTML in your Webflow pages

## Tables&#x20;

Create an Embed on the page and paste in this style.  It will style any tables within HTML.

{% hint style="info" %}
This particular styling uses a white border coloring, and assumed a darkmode background.  Adjust that to your style guide.&#x20;
{% endhint %}

```html
<style> 
.w-richtext table {
  border-collapse: collapse;
  width: 100%;
}

.w-richtext td {
  border: 1px solid #ffffff;
  padding: 8px;
  vertical-align: top;
}

.w-richtext tr:first-child td {
  background-color: #2f2f2f;
  color: #ffffff;
}
</style> 
```


# Hyperspeed

Minimize bandwidth use and maximize performance for your Webflow-hosted site

{% hint style="info" %}
**Hyperspeed is our most-requested Hyperflow App.**

*See the following section for details.*&#x20;
{% endhint %}


# Hyperflow Setup

**Sygnal Hyperflow & Hyperspeed run on Cloudflare.** This provides a world-class edge-caching framework, full firewall support, and many more capabilities that we leverage to optimize your site's caching and delivery.&#x20;

Our setup process has three phases;

1. [Migrating your DNS to Cloudflare ](/install/cloudflare-dns-setup)
2. [Installing and configuring Hyperspeed](/install/hyperflow-installation) for your site&#x20;
3. ( Optional ). [Setting up monitoring and alerting](/install/monitoring-and-maintenance-setup) for your site ( *highly recommended*, but optional ).&#x20;

## Installation&#x20;

For each service,&#x20;

cd into that service codebase&#x20;

```
npx wrangler deploy --config wrangler.navi.jsonc
```

For the main Hyperflow app `hyperflow`  &#x20;

## Config

e.g. `wrangler.navi.jsonc`&#x20;

### Vars

Ensure the desired PATH\_HANDLERS and REWRITE\_HANDLERS are specified.&#x20;

```json
		"UPSTREAM_ORIGIN": "https://www.tournewzealand.com",
		"ORIGIN": "https://www.tournewzealand.com",

		// List of all RPC workers that support fetch() 
		// Determines order of execution 
		"PATH_HANDLERS": [
			{
				"binding": "HF_LLMS",
			},
			// {
			// 	"binding": "HF_WFX",
			// },			
			// {
			// 	"binding": "HF_INDEXNOW",
			// },			
		],

		// List of all RPC workers that support rewrite() 
		// Determines order of execution 
		"REWRITE_HANDLERS": [
			// {
			// 	"binding": "HF_WFX",
			// },
		],
		
		"POSTHOG_API_KEY": "phc_CfW1VAtR3ueFV3so5hxXQwb1l0RwsarirNw5M39Dz9T" // tournewzealand.com 
```

### Services

List only microservices we're connecting to.&#x20;

Make certain to update the binding names to the correct service.&#x20;

```json
	"services": [
		{
			"binding": "HF_LLMS",
			"service": "hf-llms-navi"
	 	},
		// {
		// 	"binding": "HF_WFX",
		// 	"service": "hf-wfx"
	 	// },
		// {
		// 	"binding": "HF_INDEXNOW",
		// 	"service": "hf-indexnow"
	 	// }
	],

```


# Cloudflare DNS Setup

DNS migration is not especially difficult however it requires access to your domain registrar, and a few key understanding of how DNS's work to ensure that the migration goes smoothly with all DNS records intact.

{% hint style="success" %}
If your domain is already using Cloudflare's DNS, then you are all set- you simply need to invite Sygnal to your Cloudflare account to install Hyperspeed.&#x20;

You can invite `mike@sygnal.com`.
{% endhint %}

If your DNS is not yet on Cloudflare;&#x20;

1. [Sygnal can setup your Cloudflare account](#sygnal-setting-up-cloudflare-for-you) and DNS for you,&#x20;
2. Or, you can [setup Cloudflare](#setting-up-cloudflare-yourself) and migrate your DNS yourself.&#x20;

## Sygnal Setting up Cloudflare & DNS for you

{% hint style="info" %}
Ideally to do this, we need access to your **domain registrar**, so that we can retrieve your current DNS zonefile, and once your Cloudflare DNS is ready, to update your nameservers.  If you use a registrar like [GoDaddy](/install/cloudflare-dns-setup/godaddy), you can invite Sygnal as a delegate.&#x20;
{% endhint %}

If those are difficult to achieve what we'll need is;

* Your [DNS zone file export](https://en.wikipedia.org/wiki/Zone_file), which is a text file listing all of your DNS entries that we need to load into Cloudflare for you.&#x20;

Once we have Cloudflare setup, we'll give you the nameservers you need to set;

* You would then set your nameservers in your registrar, so that your DNS switches over to your new Cloudflare setup.

### Sygnal will Invite you to your Cloudflare Account

{% hint style="success" %}
You'll have full access to your Cloudflare account, and to your DNS for future updates you want to make. Please give us the email address you want us to invite as the account owner.&#x20;
{% endhint %}

### You will then activate Cloudflare's Pro plan&#x20;

{% hint style="info" %}
We recommend you select **monthly billing** ( $25/mo ) until your Hyperspeed is fully setup.  At that point, you can switch to **annual billing** ( $20/mo ). &#x20;

You can also start with Cloudflare's Free plan, and then add the Pro billing after your DNS setup is complete. *You do not need the Pro plan for the DNS features alone.* &#x20;
{% endhint %}

## Setting up Cloudflare Yourself

If you choose to setup Cloudflare yourself, here's an overview.&#x20;

### Create your Cloudflare Account

Start here;

<https://www.cloudflare.com/plans/>

*You will need the Pro account.*&#x20;

{% hint style="info" %}
We recommend you select **monthly billing** ( $25/mo ) until your everything is fully setup.  At that point, you can switch to **annual billing** ( $20/mo ). &#x20;

You can also start with Cloudflare's Free plan, and then add the Pro billing after your DNS setup is complete. *You do not need the Pro plan for the DNS features alone.* &#x20;
{% endhint %}

### Migrate your site's DNS to Cloudflare

Here's a video tutorial that will give you the basic approach.&#x20;

{% embed url="<https://www.sygnal.com/lessons/using-cloudflare-dns>" %}

### Ensure that DNSSEC is disabled at your domain registrar&#x20;

See your domain registrar's admin interface and documentation for this.&#x20;

*Notes on* [*GoDaddy*](/install/cloudflare-dns-setup/godaddy) *here.*&#x20;

### Change your Domain's Nameservers to point to Cloudflare

See your domain registrar's admin interface and documentation for this.&#x20;

*Notes on* [*GoDaddy*](/install/cloudflare-dns-setup/godaddy) *here.*&#x20;

### Invite Sygnal to your Cloudflare Account

Once your DNS is fully setup and Cloudflare shows as "active", you'll need to invite our team so that we can install Hyperspeed for you.&#x20;

* *Permissions.* Full admin access is best, but most importantly we need;&#x20;
  * Workers access
  * Full admin access to the specific domain Zone being proxied

{% hint style="info" %}
Use **<mike@sygnal.com>** for the invitation.&#x20;
{% endhint %}

&#x20;


# GoDaddy

Note on migrating your DNS from GoDaddy to Cloudflare

## GoDaddy delegate access&#x20;

If your domain name is registered with GoDaddy, and you are using GoDaddy's DNS services, then you can invite Sygnal as a "delegate" so that we can perform your DNS migration.&#x20;

{% hint style="info" %}
Invite **<mike@sygnal.com>**.&#x20;
{% endhint %}

{% embed url="<https://www.loom.com/share/6b4444fc860f4e078566d80e09c9fe19>" %}

## Important Configuration Notes

## Disable DNSSEC

{% hint style="warning" %}
It's very important to ensure that DNSSEC is disabled before your DNS is migrated.&#x20;
{% endhint %}

{% embed url="<https://www.godaddy.com/help/turn-dnssec-on-or-off-6420>" %}

## Change Nameservers

{% embed url="<https://dcc.godaddy.com/control/portfolio/guntry.com/settings?subtab=nameservers>" %}

## After changing Nameservers

Use a tool like whatsmydns to check for your NS propagation

{% embed url="<https://www.whatsmydns.net>" %}


# Hyperflow Installation

## What we need to set you up

To install Hyperspeed, Sygnal needs;  &#x20;

* **Access to your Cloudflare account.** If we setup your Cloudflare account ourselves, we're all set. If you have setup your own Cloudflare account,  we'll need;
  * *Permissions.* Full admin access is best, but most importantly we need;&#x20;
    * Workers access
    * Full admin access to the specific domain Zone being proxied
* **Cloudflare Pro setup on your account.** This is the point at which you'll need to setup Cloudflare Pro on your Cloudflare account.&#x20;
* **Access to your Webflow workspace.** Invite us as an Agency guest.&#x20;
  * We only need this if you want Hyperspeed's [Purge Cache on Site Publish](/hyperspeed/hyperspeed-caching-features/purge-cache-on-site-publish) feature installed.&#x20;
  * If that's difficult, we can give you instructions on how to install the webhook yourself.&#x20;

{% hint style="success" %}
Both invites can be issued to **<mike@sygnal.com>**.&#x20;
{% endhint %}

* **Site optimization notes.** Any details on specific areas of your site that need optimization;
  * Areas with extremely high traffic ( besides the home page )&#x20;
  * Areas with unusually large assets, or a lot of assets;&#x20;
    * Photo gallery pages
    * Pages with background video assets

## Some highlights of our setup process

Cloudflare setup;

* Create your Cloudflare account
* Setup your DNS
* Migrate your nameservers&#x20;
* Invite you with full owner permissions&#x20;

Hyperspeed installation;

* Install Sygnal Hyperspeed in your Cloudflare account&#x20;
  * Configure Hyperspeed for your site&#x20;
* Configure your DNS for reverse proxy mode
* Configure Cloudflare's caching rules
* Configure Cloudflare's SSL rules
* Other custom configurations&#x20;

Webflow installation; &#x20;

* Install Hyperspeed's [Purge Cache on Site Publish](/hyperspeed/hyperspeed-caching-features/purge-cache-on-site-publish) feature&#x20;


# Micro-service RPC Interface

```
async fetch(request: Request)
```


# Monitoring & Maintenance Setup

We are quite thorough in our monitoring & maintenance work.&#x20;

## Direct Monitoring & Alerting

We'll be runnig 24/7/365 monitoring and alerting on your site so that our team is immediately notified of any outages.

We can also setup a status page for you on your site, e.g. `status.mysite.com` which allows you to see your status.&#x20;

{% hint style="success" %}
We won't need anything from your team to set this part up.&#x20;
{% endhint %}

## Additional Monitoring&#x20;

Aside from the site performance and uptime, we are also always looking for ways to improve the performance of your site from a business perspective.&#x20;

A central part of this is your site's technical SEO.&#x20;

If you are currently monitoring your site with AHrefs or ScreamingFrog, you can invite us to those services so that we can keep an eye on specific issues your facing.&#x20;

The reason is that there are a lot of things we can enhance in Webflow's HTML that will benefit technical SEO, but we need to see what your SEO monitoring services identify as problems in order to help you here.&#x20;

* Invitation to AHrefs and/or ScreamingFrog
* Invitation to Google Search Console

{% hint style="success" %}
Invitations can be sent to **<mike@sygnal.com>**.&#x20;
{% endhint %}

## &#x20;


# About Hyperspeed

What is Sygnal Hyperspeed and what does it do?

## Sygnal Hyperspeed

As of April 2024, **Sygnal Hyperspeed** is now a fully mature product with new releases happening several times a month.

It offers full asset coverage including images, video, CMS assets, on your content including foreground, background, and responsive images throughout your site.&#x20;

### Monitoring & Maintenance Program

In June 2024, we've launched our monitoring & maintenance program which allows you to see the performance benefits you're getting and to ensure maximum uptime for your site. Our team is continually looking for improvements- even SEO advantages that we can add to your site.&#x20;


# Hyperspeed Releases

## 0.1.10 - Released 17-Jun-2024

* Revised redirect handling. Webflow-redirected pages are now directly redirected, and the redirect is edge-cached for 4 hours in a standard configuration.&#x20;
* SEO;&#x20;
  * Adds `<og:url>` based on your canonical URLs.&#x20;

## 0.1.9 -

* Caching focused on the edge cache durations, and minimizes browser cache durations. The goal is to make it possible to deploy updates instantaneously
* Asset coverage;&#x20;
  * Revised the CDN handler to recognize all asset URLs originating from `website-files.com` or `webflow.com` as being Webflow asset URLs. Better for future-proofing.&#x20;
* API;&#x20;
  * Augmented API with some monitoring features.&#x20;
  * Prototyping stats features.&#x20;

## 0.1.8 -

* Asset coverage;&#x20;
  * Added Webflow's new asset origin, `https://cdn.prod.website-files.com` to the list of recognized Webflow asset CDNs.&#x20;
* API;&#x20;
  * Introduced new Hyperspeed API.&#x20;

## 0.1.7 -&#x20;

* Revised image and media caching to 1 year.&#x20;
* Asset coverage;&#x20;
  * Updated CSS coverage for asset URLs to improve identification of assets with quoted URL variations.&#x20;

## 0.1.6 -&#x20;

* Asset coverage;&#x20;
  * Added `<style>` element coverage
  * Added `style` attribute coverage for background images&#x20;

## 0.1.5 -&#x20;

* Asset coverage;&#x20;
  * Added CSS coverage, for CSS-referenced asset URLs, such as background images and SVGs
  * Added video poster image caching&#x20;

## 0.1.4 -&#x20;

* Asset coverage;&#x20;
  * Added video caching

## 0.1.3 -&#x20;

* Added debugging and KV configurations&#x20;

## 0.1.2 -&#x20;

* Asset coverage;&#x20;
  * `<img srcset>` attributes&#x20;

## 0.1.1 -&#x20;

* Expanded caching control and durations.&#x20;

## 0.1.0 - Initial Release

* Asset coverage;
  * `<img src>` elements


# Hyperspeed Caching Features

## Asset Caching&#x20;

* Identify and edge-cache all Webflow image & video assets to maximize performance for your Webflow-hosted site. Excellent coverage;
  * `<img src>` caching
  * `<img srcset>` responsive image caching
  * `<video>` caching, including Webflow background videos&#x20;
  * Background images in `style` attributes
  * Background images in the Webflow CSS file&#x20;

## Bandwidth & Traffic Management

* Minimize traffic to Webflow's origin servers, to assist you in staying within Webflow hosting plan limits.&#x20;
  * Typically a 90% reduction in bandwidth use.&#x20;
* Detailed reporting.&#x20;

##


# Purge Cache on Site Publish

**Sometimes you want your new content to be seen&#x20;*****immediately*****.**

In Hyperspeed's edge-cached platform, we're delivering a copy of your site from servers nearest your website users, so that they get content as quickly as possible. This means that website updates won't be seen until the cache expires. &#x20;

{% hint style="info" %}
Our typical cache duration for HTML, CSS, and JS files is **4 hours**.&#x20;

If you want to wait 4 hours for the world to see your updates, then you don't necessarily need to chache purge feature. If you want your updates to be seen immediately, then cache purge is important for your setup.&#x20;
{% endhint %}

## How Purge Cache on Site Publish Works

Hyperspeed includes the ability to purge the edge cache. We integrate that with your Webflow site, so that publishing your site will automatically clear the cache, to ensure your new content is delivered as soon as possible.&#x20;

{% hint style="warning" %}
Remember that a cache purge means that the Cloudflare edge cache is fully emptied, and must be rebuilt. This will increase traffic to Webflow's origin servers until Cloudflare's cache has re-acquired all documents and assets for your site.

Typically this is not a significant concern, but if you are publishing your site several times a day, and one of your goals is to minimize bandwidth to Webflow's origin servers, be aware of the impacts here.&#x20;
{% endhint %}


# Hyperspeed Security Features

## Security

* Bot & DDoS attack protection
* Firewall monitoring and control&#x20;

## Advanced Security Options

Custom Security Headers


# Hyperspeed SEO Features

## Asset Paths

Instead of being prefixed with a generic path like `cdn.prod.website-files.com`, all of your assets are prefixed with your own custom domain.&#x20;

### Advanced Asset Path Options

Suppose your domain is `mysite.com`. Typically Hyperspeed delivers assets as `assets.mysite.com`, but it is possible for us to configure them specially as e.g. `https://www.mysite.com/images/...`&#x20;

## Open Graph&#x20;

* `<og:url>` composed from your canonical URL.&#x20;

### Advanced Open Graph Options

Hyperspeed caches assets for `og:image` however if you've used Webflow's asset optimizaton tool, the underlying asset will be a WEBP.&#x20;

Some social media networks such as LinkedIn do not handle WEBPs well.  In an advanced setup, we can specially prepare a JPEG from your WEBP and deliver that in its place.&#x20;


# Hyperspeed Advanced & Custom Features

Custom features we can add to your Hyperspeed installation

## Security Headers

* Advanced security headers options
  * HSTS, etc.&#x20;

## Image Optimization&#x20;

* Image optimization to WEBP + resizing options.&#x20;
* Image format-specific variants for specific needs, e.g. `og:image` tags where many services cannot support WEBPs. &#x20;

## Custom Features

{% hint style="success" %}
Sygnal can custom build other Hyperflow features into your Hyperspeed setup.
{% endhint %}

* Liquid paths
* Special sitemap re-engineering
* Site merge

And many more...


# Hyperspeed Monitoring & Maintenance

In **June 2024**, Sygnal introduced our Hyperspeed Monitoring & Maintenance plan.

## Monitoring

* 24/7 monitoring & alerting of any outages on your site
* Weekly review of
  * Caching performance, to ensure optimal coverage
  * Firewall traffic / attack anomalies

## Maintenance

* Automatic release of new updates
  * Currently we release new Hyperspeed versions 2 to 3 times per month&#x20;
* Contact our dev team directly regarding any special configuration changes you need

## Pricing

Monitoring & Maintenance&#x20;

**$180/mo or $1,440/yr ( 20% discount )**&#x20;

### Maintenance-only

Not yet available, but may be released in late 2024.&#x20;

Ideally, clients have full monitoring in place at the b

About 3 months in, it may be suitable to switch to a maintenance only plan. You'd be responsible for your own monitoring, and alerting us, but we'll be releasing regular new platform updates to your setup to ensure that changes in Webflow and in Cloudflare are handled ongoing.&#x20;


# Additional Notes

Bring your Webflow hosted site's performance into the high 90's

## Goals

* Maximize the performance of Webflow-hosted sites
* Optimize images
* Edge-caching
  * Ability to purge cache when necessary&#x20;
    * Site-publish = full purge
* Zero / minimal monthly hosting costs for optimization and caching

## Features

* Images
  * Automatically detect and optimize all HTML-referenced images on the site
    * HTML Images ( `src` )
    * HTML Media srcset images ( `srcset` )
  * Configure the from and to formats
    * e.g. which to WEBP convert, which not to for animation purposes&#x20;

## Future

* Proxy other image types like PDF
* Possibly optimize them&#x20;
* CSS-referenced images such as background images&#x20;
* Ability to zone and classify image rules;
  * By page
  * Page section ( attributes )
  * Custom attributes override directly on image&#x20;
  * &#x20;

`https://assets-global.website-files.com`

`https://assets.website-files.com`

\`HTML Images ( `src=` )

HTML Media srcset images ( `srcset=` )

CSS background images

Future

alt domains

user images?&#x20;

uploaded images?&#x20;

## Configurations

### &#x20;<a href="#enable-transformations" id="enable-transformations"></a>

<br>

## Cassette

assets.sygnal.com

<https://1assets-global.website-files.com>


# Hyperspeed API

## Statistics

{% hint style="danger" %}
Prototyping. Not yet available.&#x20;
{% endhint %}

```
/.sygnal/hyperflow/hyperspeed/stats
```

## Version

Determine the version of Hyperspeed installed.&#x20;

```
/.sygnal/hyperflow/hyperspeed
```

## Purge Cache

Purge the cache fully.&#x20;

```
/.sygnal/hyperflow/hyperspeed/purge-cache
```

### Purge Specific

{% hint style="danger" %}
Prototyping. Not yet available.
{% endhint %}

### Purge HTML Only

{% hint style="danger" %}
Prototyping. Not yet available.
{% endhint %}

```
/.sygnal/hyperflow/hyperspeed/purge-cache/html
```

## View Config

View Hyperspeed configuration. *Sanitized.*

```typescript
/.sygnal/hyperflow/hyperspeed/config
```

## Info

### Page List

A list of all pages, parsed from the Sitemap.&#x20;

{% hint style="danger" %}
Not yet implemented.
{% endhint %}

```
/.sygnal/hyperflow/hyperspeed/info/pages
```

Include alt languages;

```
/.sygnal/hyperflow/hyperspeed/info/pages?all
```


# Monitoring

What we want to know;&#x20;

* Any errors or problems occurring
  * Critical system failures&#x20;
  * Minor anomalies&#x20;
* Warnings, like high usage
* Information;
  * Performance
  *

## Mechanisms

* All URLs deliver catastrophic errors directly&#x20;
* Special endpoints deliver recent errors
  * Human-readable log
  * Machine-readable log
* Alerting, site down&#x20;

## Catastrophic Errors

Push to a Log

Report a detectable error, e.g. 500+&#x20;

Special endpoints for monitoring

## Performance Stats

## Coverage Analysis

* Full site analysis
* Look for rogue files delivered by Webflow origin&#x20;


# Information

## Response Headers

| Header                | Notes                                                        | Example                       |
| --------------------- | ------------------------------------------------------------ | ----------------------------- |
| Hf-Hyperspeed         | The version of Hyperspeed used in the generation of the page | e.g. v0.1.6                   |
| Hf-Hyperspeed-Handler |                                                              | e.g. asset                    |
| Hf-Hyperspeed-Tms     | Page generation time in UTC.                                 | e.g. 2024-05-26T11:37:29.166Z |


# JS

## Known path

```
/site.js
```


# CSS

## Known path

```
/site.css
```

Something that can be easily purged but is also prettier.


# Hyperflow Purge Cache

Purge the proxy cache, when your Webflow site is republished

Purges the global Cloudflare cache for a site.  This works with our caching-proxy configuration and is intended to be automatically triggered by Webflow's site publish Webhook.&#x20;

## R\&D&#x20;

* Individual CMS item publication and cache purging
* Plus Webflow\.js etc.&#x20;

## Configuration

Learn more about [Hyperflow configuration](broken://pages/0JKoGxXthjJPP7V55Q3E) here.

### KV Store

Service Name: `purge-cache`&#x20;

```json
{
  "version": 1, 
  "zoneId": "28fb418cb8b59d549384f34fe0decd07" 
}
```

### Secrets

Requires a Cloudflare API key, which has purge cache permissions on the desired zone;&#x20;

Account > Workers & Pages > cloudflare-clear-cache > Settings > Variables

Add CLOUDFLARE\_API\_TOKEN (value) Encrypted&#x20;

## Deployment

### Worker Routes

Variable.&#x20;

We recommend a route like;

* `*DOMAIN/_purge`
* `*DOMAIN/_hf/purge-cache`
* `*hf.DOMAIN/purge-cache`

### Webflow API Webhook

Get your SiteID

<https://developers.webflow.com/reference/list-sites>

Create your Webhook

<https://developers.webflow.com/reference/create-webhook>

* site\_id = your site ID, above
* triggerType: `site_publish` - Sends a [site\_publish](https://developers.webflow.com/reference/create-webhook#site_publish) event
* url - your URL

## Future

<https://developers.cloudflare.com/workers/learning/how-the-cache-works/>

<https://developers.cloudflare.com/workers/examples/cache-api/>

<https://blog.cloudflare.com/introducing-the-workers-cache-api-giving-you-control-over-how-your-content-is-cached/>


# Purge Triggers

## Site Published

Purge all HTML

<https://developers.webflow.com/data/reference/all-events#site_publish>

```
curl -X POST "https://api.webflow.com/sites/{site_id}/webhooks" \
-H "Authorization: Bearer {your_access_token}" \
-H "Content-Type: application/json" \
-d '{
    "triggerType": "site_publish",
    "url": "https://your-webhook-url.com"
}'
```

## CMS Item Published

Option, purge all HTML

If possible;

* Identify item page, purge it&#x20;
* Identify pages which use this CMS data in a collection list, purge it&#x20;

<https://developers.webflow.com/data/reference/all-events#collection_item_changed>

<https://developers.webflow.com/data/reference/all-events#collection_item_deleted>

<https://developers.webflow.com/data/reference/all-events#collection_item_unpublished>

```
curl -X POST "https://api.webflow.com/sites/{site_id}/webhooks" \
-H "Authorization: Bearer {your_access_token}" \
-H "Content-Type: application/json" \
-d '{
    "triggerType": "item_publish",
    "url": "https://your-webhook-url.com"
}'
```


# Purge HTML Only

Concept

Pull HTML list from sitemap

Purge those URLs only


# Quickstart

{% hint style="info" %}
We're using the subdomain approach as it's likely we'll evolve aspects of HF into a Cloudflare app.&#x20;
{% endhint %}

Given;

* **DOMAIN** e.g. sygnal.com
  * Registered on CF, with DNS and proxy setup&#x20;
* **ZONE-ID** for that domain

## Setup

### DNS

Add a CNAME for hf to @&#x20;

Set it to proxy on&#x20;

<figure><img src="/files/5PGvqsJO943j70P4yY7D" alt=""><figcaption></figcaption></figure>

### Config

Add a KV store config of to CONFIG, with your ZONE-ID. &#x20;

Key; **`DOMAIN`**`:purge-cache`

```json
{
  "version": 1, 
  "zoneId": "ZONE-ID" 
}
```

### Worker Route

`*hf.`**`DOMAIN`**`/cache/purge` -> `cloudflare-clear-cache`

### Verify

<https://hf.DOMAIN/cache/purge>

A successful response is;&#x20;

```
Cache Purge Initiated Successfully
```

### Webflow Webhook

Get your site id

<https://developers.webflow.com/reference/list-sites>

e.g. 62296a1920ec667f814208e2

<https://developers.webflow.com/reference/list-webhooks>

#### Create Webhook

<https://developers.webflow.com/reference/create-webhook>

Paste in site\_id

Select site\_publish&#x20;

Paste in your HF URL

e.g. <https://hf.ponsonbydoctors.co.nz/cache/purge>

Click Try It!

Check for a valid 201 response e.g.;

<figure><img src="/files/XnXXxfyhpCpr03wczrhS" alt=""><figcaption></figcaption></figure>


# Content Coverage

## v0.1.6

? Mirage

`<img...`

`data-cfsrc`&#x20;

```
                <a href="/" aria-current="page" class="brand-link-2 w-nav-brand w--current">
                    <script type="text/javascript" style="display:none">
                        //<![CDATA[
                        window.__mirage2 = {
                            petok: "Khx7riGzyJ5iBsbhS0vajbiHCxX8JOTe42bwc8dEsoM-86400-0.0.1.1"
                        };
                        //]]>
                    </script>
                    <script type="text/javascript" src="https://ajax.cloudflare.com/cdn-cgi/scripts/04b3eb47/cloudflare-static/mirage2.min.js"></script>
                    <img loading="lazy" alt class="image-3" data-cfsrc="https://assets-global.website-files.com/59b8d49f7fdf9700017d780f/6077ab72eb33aa5e2f2ba0a1_sygnal-2.png" style="display:none;visibility:hidden;"/>
                    <noscript>
                        <img src="https://assets-global.website-files.com/59b8d49f7fdf9700017d780f/6077ab72eb33aa5e2f2ba0a1_sygnal-2.png" loading="lazy" alt="" class="image-3"/>
                    </noscript>
                </a>
```

CSS

```
.slide-two-image-three {
  background-image: url("https://assets-global.website-files.com/59b8d49f7fdf9700017d780f/64a7d3093b57d3e024bbe667_Business%20Expert%20(3).webp");
  background-position: 50%;
  background-size: cover;
  width: 945px;
  height: 1080px;
}
```


# Special File Handling

## robots.txt

if not existing, create a static allow-all response&#x20;

## sitemaps.xml

refer sitemap.xml

## favicon.ico

404


# Caching

## Configuration

Durations

## Hf-Hyperspeed-Tms

Store generation time in cache&#x20;


# Image Handler

```typescript

    // Format
    // https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>

    // https://milkmoonstudio.com/cdn-cgi/image/f=auto,quality=90/
    // format
    // quality
    // https://developers.cloudflare.com/images/transform-images/ 

    /*
<img 
height="320" 
src="https://assets-global.website-files.com/59b8d49f7fdf9700017d783a/64cc27e46f98d895545ba619_memetican_information_tables_on_a_webpage._with_rows_and_column_c7ff6d47-c98b-4f46-b6a9-9b64ee9.webp" 
alt="" 
sizes="(max-width: 479px) 100vw, (max-width: 767px) 91vw, (max-width: 991px) 43vw, (max-width: 1439px) 28vw, 358px" 
srcset="https://assets-global.website-files.com/59b8d49f7fdf9700017d783a/64cc27e46f98d895545ba619_memetican_information_tables_on_a_webpage._with_rows_and_column_c7ff6d47-c98b-4f46-b6a9-9b64ee9-p-500.webp 500w, https://assets-global.website-files.com/59b8d49f7fdf9700017d783a/64cc27e46f98d895545ba619_memetican_information_tables_on_a_webpage._with_rows_and_column_c7ff6d47-c98b-4f46-b6a9-9b64ee9-p-800.webp 800w, https://assets-global.website-files.com/59b8d49f7fdf9700017d783a/64cc27e46f98d895545ba619_memetican_information_tables_on_a_webpage._with_rows_and_column_c7ff6d47-c98b-4f46-b6a9-9b64ee9-p-1080.webp 1080w, https://assets-global.website-files.com/59b8d49f7fdf9700017d783a/64cc27e46f98d895545ba619_memetican_information_tables_on_a_webpage._with_rows_and_column_c7ff6d47-c98b-4f46-b6a9-9b64ee9.webp 1536w" 
class="autofit full-width" 
>
*/

    // format: string = "auto";
    // quality: number = 90;
```


# Dev Setup

/\*\*

* Dev Setup
*
* Add to HOSTS
* C:\Windows\System32\drivers\etc\hosts
* 127.0.0.1 z.DOMAIN.COM
* 127.0.0.1 z.assets.DOMAIN.COM
* 127.0.0.1 z.images.DOMAIN.COM \*/


# Hyperflow Inline SVGs

## Goals

* Optimize SVGs&#x20;
* Inline SVGs
  * currentColor support&#x20;

Take an external SVG, and inline it


# Hyperflow Image Optimization

## Goals

* Optimize all images
  * HTML Images ( src )
  * HTML Media sercset images ( srcset )
  * Background Images
* Domain consistency for SEO&#x20;
* Edge-cache non-optimized images
* Minimal monthly hosting costs for optimization and caching

## Features

### Coverage

|            | Present                                   | Future                                                                           |
| ---------- | ----------------------------------------- | -------------------------------------------------------------------------------- |
| Coverage   |                                           | CSS Background Images                                                            |
| Asset URLs | `https://assets-global.website-files.com` | <ul><li><code><https://assets.website-files.com></code></li><li>Others</li></ul> |
|            |                                           |                                                                                  |

### Options

|                         |              |                                             |
| ----------------------- | ------------ | ------------------------------------------- |
| Multiple configurations |              | <p>Applied by;<br>- Custom attributes</p>   |
| Ignore image            |              | <ul><li>No proxy, no optimization</li></ul> |
| Quality                 | Fixed at 90% |                                             |
| Transform types         | Auto         | <ul><li>From and to types</li></ul>         |

* Images
  * Automatically detect and optimize all HTML-referenced images on the site
    * HTML Images ( `src` )
    * HTML Media srcset images ( `srcset` )
  * Configure the from and to formats
    * e.g. which to WEBP convert, which not to for animation purposes&#x20;

## Future

* Proxy other image types like PDF
* Possibly optimize them&#x20;
* CSS-referenced images such as background images&#x20;
* Ability to zone and classify image rules;
  * By page
  * Page section ( attributes )
  * Custom attributes override directly on image&#x20;
  * &#x20;

`https://assets-global.website-files.com`

`https://assets.website-files.com`

\`HTML Images ( `src=` )

HTML Media srcset images ( `srcset=` )

CSS background images

Future

alt domains

user images?&#x20;

uploaded images?&#x20;

/\*\*

* OPTIONS
* normalize zone string to [www](http://www).
* convert jpg to webp
* convert png to webp
* convert gif to webp
* convert svg to webp
* convert webp to webp
* questions regarding animation support
* quality
* cache settings - infinite
* added features like watermarking
*
* eliminate responsive images
* standardize responsive images
* fix 1vw's
*

\*/

## Configurations

### &#x20;<a href="#enable-transformations" id="enable-transformations"></a>

<br>

## Cassette

assets.sygnal.com

<https://1assets-global.website-files.com>


# Hyperflow Editor

Separate editor app

Direct to API

Edit CMS items directly

Create new CMS items

Template support&#x20;

* Defaults support

Logical rules support, e.g.

* Dates, numbers

Numeric

## Autofeeds?&#x20;


# Future

## RSS Asset Proxying

Webflow's RSS can contain image references as well;&#x20;

{% code overflow="wrap" %}

```html
<media:content url="https://uploads-ssl.webflow.com/5b763da3d25345967394ee90/5eff4af57f21002a6ba12327_How%20Much%20Sleep%20Debt%20is%20Good%20vs%20Bad_.png" medium="image"/><media:thumbnail url="https://uploads-ssl.webflow.com/5b763da3d25345967394ee90/5eff4af57f21002a6ba12327_How%20Much%20Sleep%20Debt%20is%20Good%20vs%20Bad_.png"/>
```

{% endcode %}

## User Monitoring

GA4 & GTM do a lot.&#x20;

CF Zaraz&#x20;

User-tracking ( cookie, UUID )&#x20;

Persistent settings, handled at RP?&#x20;

Monitoring files not coverably by script-based trackers

* e.g. RSS&#x20;

Raid monitoring, i.e. sequential images, bot download&#x20;

## Secure File access

* Auto replace e.g. PDF URL requests
* Option to secure them
  * Cookie-only access
    * Must have logged in successfully
      * Then login page has cookie
    * OR WUA gating&#x20;

## User Accounts Enhancements&#x20;

## JS & CSS known paths

Rather than Webflow CDN.&#x20;

## Response Headers

### `Hf-Hyperspeed-Tms`

* Change to UTC

## Debug mode

When a certain request header is included, handle requests specially.

Pass JSON config?&#x20;

## Editor?

## Image Optimizations

* Automatic WEBP conversion, without the need to run a tool
  * Idea for client-managed sites where you cannot control what assets they upload through the editor, e.g. to their blog&#x20;
* Automatic resizing options to prevent obscenely oversized client images&#x20;

## Image Enhancements

* Watermarking
* Upscaling&#x20;
* Inline SVGs - import from externally referenced files
  * Convert color to currentColor&#x20;

### Possible Image AI Enhancements

* Random image generation from keywords and page content&#x20;
* Depth maps for Fake 3D images&#x20;
* Special uses, e.g.;&#x20;
  * Automatically theme your team photos with variations, cartooning, manga, etc on a random basis.&#x20;

&#x20;


# Webflow Notes

## Hosting Plan Limits&#x20;

| Site Plan  | Bandwidth (mo.) | Visitors (mo.) |
| ---------- | --------------- | -------------- |
| Free       | 1GB             | 1k             |
| Basic      | 50GB            | 250k           |
| CMS        | 200GB           | 250k           |
| Business   | 400GB           | 300k           |
| Enterprise | negotiable      | negotiable     |


# Troubleshooting

## Error code: 525

SSL Handshake error.

It means your configuration for Hyperspeed is invalid and that your underlying Webflow certificate has expired.

```
error code: 525
```

## Solutions&#x20;

## Solution #1: Correct your Hyperspeed Config

Update your HF config.

### Solution #2: Renew your Webflow Certificate.

1. Find the `www` record in your DNS, edit it, and switch off the proxying option, and save it.

<figure><img src="/files/kJJssQ7D3jzkXYwlpeLi" alt=""><figcaption></figcaption></figure>

2. Wait a about 30 seconds, refreshing any Webflow page that has the 525 error.  Webflow will regenerate its SSL certificate.
3. Re-enable Proxy on your `www` CNAME record

{% hint style="info" %}
This will give you approximately 3 months before the certificate expires again.&#x20;
{% endhint %}


# Kingside Castle (O-O)

Protect your Webflow-hosted assets with Sygnal's "short castle" manouvre.

{% hint style="info" %}
**IMPORTANT**\
Sygnal's **Kingside Castle** manouvre should only be performed when Sygnal Hyperspeed is already installed on your site.  Otherwise it has only a short-term benefit, since your new asset URLs will be exposed for leeches to re-acquire and update their asset links.&#x20;
{% endhint %}

Goals;

* Disconnect "leeches" who are stealing your content by embedding your live Webflow assets directly in their own site, from Webflow's production CDN URLs, at your own bandwidth expense.&#x20;

Problems;

* Webflow's assets CDN uses a Webflow-owned domain, which means...&#x20;
  * We cannot directly reverse-proxy it
  * We cannot directly block access to it from outside parties
  * We have zero statistics on who is accessing it, or on the referring site&#x20;
  * We have no ability to identify anomalies or implement rules via a WAF&#x20;
* Webflow's assets CDN traffic counts towards your plan limit, so leeches count against your bandwidth quota&#x20;

## Approach

* Setup a Hyperspeed to rewrite all asset URLs
  * Obfuscate them so that the underlying Webflow CDN URL is in-determinable by a viewer&#x20;
  * Cache them, to offload Webflow traffic
  * Optionally, secure them from "simple" leeches
    * via Referrer check

Then, perform the **Kingside Castle**;&#x20;

* Clone your Webflow site
  * Move the plan to the clone
  * Move the domain to the clone
* Unpublish the old site
  * Verify the old asset URLs are now inaccessible&#x20;
* Perform any updates needed for external integrations
  * Apps installs and configurations
  * API key generation&#x20;
  * Automations&#x20;
    * Whalesync
  * Integrations
    * CMS ItemID re-synchronization with external systems
  * etc.

## Results

* All of the original Webflow CDN URLs are now invalid&#x20;
* All of the new Webflow CDN URLs are un-knowable to leeches&#x20;
* All access control is now centralized in Hyperspeed&#x20;
  * Including your Webflow CDN assets&#x20;
* All assets are delivered by cache, so leech traffic no longer impacts your Webflow bandwidth
* Leeches can be further blocked with custom asset routing with Hyperspeed customizations&#x20;
  * Such as a referrer check &#x20;

​


# Queenside Castle (O-O-O)

Protect your Webflow-hosted assets with Sygnal's "long castle" manouvre.

{% hint style="info" %}
Sygnal's **Queenside Castle** manouvre is an extension of our **Kingside Castle** manouvre.  See [those docs](/advanced/kingside-castle-o-o) as well to fully understand the solution.&#x20;
{% endhint %}

Goals;

* Disconnect "leeches" who are hosting your Webflow assets directly in their own site
* Replace Webflow's asset hosting with your own, and control all asset hosting 100%&#x20;
  * Ability to replace and update files like PDFs or videos directly&#x20;
  * Full access control to assets&#x20;
  * Ability to directly delete assets
  * Full stats on who is access your assets and from where&#x20;
* Downstream compatibility with Webflow's designer and ongoing publishing processes&#x20;
  * i.e. changes in Webflow, new assets added, etc will be automatically picked up and cloned to your private asset store&#x20;

## Approach

Setup Hyperspeed, and perform the [Kingside Castle](/advanced/kingside-castle-o-o).

Then;&#x20;

* Setup a personal S3 bucket.&#x20;

Hyperspeed is custom extended for your setup to include;&#x20;

* On an asset request;
  * Hyperspeed checks your private asset store first
  * If no match found, it then checks Webflow's store
    * If the asset is found, it clones the asset to your bucket
    * If not found, records an internal 404 block for 1 day to prevent multiple requests

## Results

* All of the [Kingside Castle](/advanced/kingside-castle-o-o) benefits
* Full control over your assets, including access control, deletion and replacement
* Full monitoring statistics and WAF control&#x20;
* Downstream compatibility with Webflow publishing
  * New assets added to the designer or CMS and published will be picked up and cloned
  * Assets added/changes to your private asset store *will not* be known to WF, but will be utilized in your public site. &#x20;

​


