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