|
| 1 | +# Detect IPFS on the Web |
| 2 | + |
| 3 | +Below is the suggested heuristic for detecting content-addressed resources on the web, and presenting additional user interface for interacting with them. |
| 4 | + |
| 5 | +The goal of this page is to provide some suggestions and best practices for web browsers and other [user agents](https://en.wikipedia.org/wiki/User_agent) that are interested in adding support for [content-addressed resources on the Web](/how-to/address-ipfs-on-web). |
| 6 | + |
| 7 | +## Detecting content-addressed resources |
| 8 | + |
| 9 | +In many cases IPFS resource can be detected just by looking at URI, especially if it is a HTTP URL pointing at a public gateway. This allows browser to upgrade transport protocol to IPFS, and removed the need for sending HTTP request to a remote server. |
| 10 | + |
| 11 | +The high level heuristic is to check, in order: |
| 12 | +- Does the `URL` follow [path or subdomain gateway](/how-to/address-ipfs-on-web/) convention? |
| 13 | +- If not, does [DNSLink](/concepts/dnslink/) with an IPFS path exist for `URL.hostname`? |
| 14 | + |
| 15 | +If any of the above is true, an user agent should be able to find a content path that can be used for data retrieval over IPFS. See the illustration below. |
| 16 | + |
| 17 | +```mermaid |
| 18 | +flowchart TD |
| 19 | + Start[Top-level navigation event] |
| 20 | + IsGateway{Is it a Gateway URL?<br/><code>foo.tld/ipxs/id/..</code><br/><code>id.ipxs.foo.com/..</code>} |
| 21 | +
|
| 22 | + Start -->|new URL in address bar| IsGateway |
| 23 | + IsGateway ==>|YES| IsPathOrSubdomain |
| 24 | + IsPathOrSubdomain -->|Path Gateway| ExtractFromPath |
| 25 | + IsPathOrSubdomain -->|Subdomain Gateway| ExtractFromSubdomain |
| 26 | +
|
| 27 | + subgraph GwURLToPath [Convert Gateway URL to a Content Path] |
| 28 | + IsPathOrSubdomain{Is the Gateway URL 'path' <br/> or 'subdomain' based?} |
| 29 | + ExtractFromPath[Extract <br/> <code>URL.pathname</code>] |
| 30 | + ExtractFromSubdomain[Read namespace <br/> and <br/>identifier from <br/> <code>URL.hostname</code> and <br/> prepend to <code>URL.pathname</code>. <br/> E.g., turn <br/><code>id.ipxs.foo.com/pathname</code> <br/> into <code>/ipxs/id/pathname</code>] |
| 31 | + end |
| 32 | +
|
| 33 | + PotentialContentPath[Found a Potential Content Path] |
| 34 | +
|
| 35 | + ExtractFromPath --> PotentialContentPath |
| 36 | + ExtractFromSubdomain --> PotentialContentPath |
| 37 | + PotentialContentPath -->|/ipxs/id/sub/path..| IsIpfsOrIpns |
| 38 | +
|
| 39 | + subgraph PathValidation [Is the Content Path valid?] |
| 40 | + IsIpfsOrIpns{Is it <code>/ipfs/</code> <br/>or <code>/ipns/</code><br/>?} |
| 41 | + ValidateRootCID{Is <code>id</code> <br/>a valid CID?} |
| 42 | + ValidateIPNSKey{Is <code>id</code> <br/>a valid CID <br/> with <code>libp2p-key</code> <br/>codec?} |
| 43 | + ValidateDNSLink{Is <code>id</code> <br/> a DNSLink name <br/> with TXT record: <br/> <code>dnslink=/ipfs/</code><br/> or <code>=/ipns/</code>} |
| 44 | +
|
| 45 | + IsIpfsOrIpns --->|/ipfs/id/..| ValidateRootCID |
| 46 | + IsIpfsOrIpns -->|/ipns/id/..| ValidateIPNSKey |
| 47 | + ValidateIPNSKey -->|NO| ValidateDNSLink |
| 48 | + end |
| 49 | +
|
| 50 | + subgraph FoundValidIPFSContent [Confirmed we've found a Valid IPFS Resource] |
| 51 | + style FoundValidIPFSContent margin-top: 50 |
| 52 | + ValidIPFSCID[Valid /ipfs/cid/.. <br/>Content Path] |
| 53 | + ValidIPNSKey[Valid /ipns/key/.. <br/>Content Path] |
| 54 | + ValidDNSLink[Valid /ipns/dnslink/.. <br/>Content Path] |
| 55 | +
|
| 56 | + ValidateRootCID ===>|YES, /ipfs/cid/..| ValidIPFSCID |
| 57 | + ValidateIPNSKey ===>|YES, /ipns/key/..| ValidIPNSKey |
| 58 | + ValidateDNSLink ===>|YES, /ipfs/dnslink/..| ValidDNSLink |
| 59 | + end |
| 60 | +
|
| 61 | + subgraph NonGwURLToPath [See if non-Gateway URL has a Content Path] |
| 62 | + IsCachedDNSLink{Does <br/> <code>URL.hostname</code> <br/> match a cached <br/> DNSLink name?} |
| 63 | + IsHeaderPresent{Is <code>X-Ipfs-Path</code> <br/> header present?} |
| 64 | + IsError{Did request fail? <br/> HTTP error>500 <br/> or network error} |
| 65 | + IsDNSLinkAtHostname{Does DNSLink exists <br/> for <code>URL.hostname</code>?<br/>} |
| 66 | + PathFromHeader[Read value from <code>X-Ipfs-Path</code>] |
| 67 | + end |
| 68 | +
|
| 69 | + IsGateway -->|NO| IsCachedDNSLink |
| 70 | + IsCachedDNSLink ==>|YES| ValidDNSLink |
| 71 | + IsCachedDNSLink -->|NO| IsHeaderPresent |
| 72 | + IsHeaderPresent ==>|YES| IsDNSLinkAtHostname |
| 73 | + IsHeaderPresent -->|NO| IsError |
| 74 | + IsError ==>|YES| IsDNSLinkAtHostname |
| 75 | + IsDNSLinkAtHostname ==>|YES| ValidDNSLink |
| 76 | + IsDNSLinkAtHostname -->|NO| PathFromHeader |
| 77 | + PathFromHeader --> PotentialContentPath |
| 78 | +``` |
| 79 | + |
| 80 | +## What to do with detected paths? |
| 81 | + |
| 82 | +### Immutable `/ipfs/cid/..` |
| 83 | + |
| 84 | +- Display "Open via IPFS" button in UI |
| 85 | + - Clicking it should open `ipfs://cid/path?query#hash` (preserving any `?query` or `#hash` from the original HTTP URL) |
| 86 | +- If "IPFS Gateway Redirect / Protocol Upgrade" feature is enabled, and the HTTP URL was a gateway one, redirect automatically to `ipfs://cid/path?query#hash` |
| 87 | + |
| 88 | +### Mutable `/ipns/key/..` |
| 89 | +- Display "Open via IPFS" button in UI |
| 90 | + - Clicking it should open `ipns://key/path?query#hash` (preserving any `?query` or `#hash` from the original HTTP URL) |
| 91 | +- If "IPFS Gateway Redirect / Protocol Upgrade" is enabled, and the original HTTP URL was a gateway one, redirect automatically to `ipns://dnslink/path?query#hash` |
| 92 | + |
| 93 | +### Mutable `/ipns/dnslink/..` |
| 94 | + |
| 95 | +- Display "Open via IPFS" button in UI |
| 96 | + - Clicking it should open `ipns://dnslink/path?query#hash` (preserving `?query` or `#hash` from the original HTTP URL) |
| 97 | +- If "DNSLink Website Redirect / Protocol Upgrade" is enabled, redirect automatically to `ipns://dnslink/path?query#hash` |
| 98 | +- It is a good practice to internally cache the fact that domain has a valid DNSLink. |
| 99 | + - TTL from TXT record can be used as a hint when to expire cache entry. |
| 100 | + - Performance can be improved further by using cached flag and revalidating it asynchronously, without blocking browser navigation. |
| 101 | + |
| 102 | +## FAQ |
| 103 | + |
| 104 | +- What if a browser does not support `ipfs://` and `ipns://` natively? |
| 105 | + - Implementation can use a [HTTP Gateway](/reference/http/gateway/) as a fallback: convert them to `//gatewayhost/ipxs/id/..` paths, or leverage the built-in URI router at `//gatewayhost/ipfs/?uri=%s` |
| 106 | +- Why should `?query` or `#hash` from the original HTTP URL be preserved? |
| 107 | + - Link could point at specific `#section` of a longer article. It is also common for JS running on a page to use `?query` and `#hash` for navigation and ad-hoc storage for some state. |
| 108 | +- Should user agent redirect when URL does not match gateway convention, `URL.hostname` does not have a valid DNSLink, but `X-Ipfs-Path` is present in HTTP response AND points at immutable `/ipfs/cid`? |
| 109 | + - This is an edge case, and we've seen that it is often a misconfiguration caused by invalid/missing DNSLink that could lead to bad UX when automatic redirect is involved: user ends up on immutable copy of a website, bookmark it or keep tab open, and miss updates when DNSLink setup is fixed. |
| 110 | + - It is suggested to not redirect this edge case, or provide a setting that controls this type of redirect. Usually, showing "Open via IPFS" in the user interface is enough for this case. |
| 111 | + |
| 112 | +## Implementation examples |
| 113 | + |
| 114 | +### Brave |
| 115 | + |
| 116 | +[IPFS is supported in Brave since 2021](https://brave.com/brave-integrates-ipfs/). Current features include `ipfs://` and `ipns://` URI support, ability to resolve them using a public or local gateway, opt-in Gateway and DNSLink redirects, and "Open via IPFS" button in the address bar: |
| 117 | + |
| 118 | +>  |
| 119 | +
|
| 120 | +### IPFS Companion |
| 121 | + |
| 122 | +Firefox and Chromium-based browsers such as Google Chrome, Microsoft Edge can be augumented with [IPFS Companion](/install/ipfs-companion/) browser extension. |
| 123 | + |
| 124 | +It provides detection of IPFS resources, redirect functionality, and a handy UI: |
| 125 | + |
| 126 | +>  |
| 127 | +
|
0 commit comments