# Make a one-time link for a demo

> Give someone a link to your local app that works once and then stops: qurl share issues single-use links by default, with no account.

Source: https://layerv.ai/guides/one-time-link-for-a-demo/

---

[← All guides](https://layerv.ai/guides/) 

# Make a one-time link for a demo

Content updated October 24, 2026.

## How do I give someone a link to my app that works only once?

With qURL™, publish the app with qurl publish, then run qurl share. With no flags the link is single-use and expires within 24 hours: the first person to open it gets a session, and the link shows “Access link invalid” after that. ngrok and Cloudflare Quick Tunnel URLs open for anyone who has them until you stop the tunnel.

## What you need

- An HTTP app running on this machine
- The qURL CLI 3.4.1 or later
- No account

## Steps

1. ### Install the qURL CLI  
On macOS, install it with Homebrew. On Linux and Windows, download the package for your platform from the latest release; the CLI page lists each one. Nothing asks you to sign up.  
```  
brew install layervai/tap/qurl
qurl --version
```
2. ### Publish the app  
The first publish creates this device’s identity, starts a background service that keeps serving after you close the terminal (while you stay logged in), and prints the app’s CRID, its stable ID. The Access row says who can open the app: a plain publish makes it private from qurl 3.4.1 on. qurl share turns the CRID into an access link, and the link is what you send.  
```  
qurl publish http://127.0.0.1:3000
```  
Published  
  Target:  http://127.0.0.1:3000  
  Access:  private — only you and the people you allow can open it  
  Status:  serving  
CRID: ae4jqpd7eaoslq7jinmjv4yikgzmcxgpjfsuobiniqnko32lpw743ivbeyha
3. ### Create a single-use link with a short fuse  
Single use is the default for apps published from the CLI. Add --ttl so an unopened link also dies quickly, and --session-duration for how long the demo may run once it starts.  
```  
qurl share <CRID> --ttl 1h --session-duration 30m
```
4. ### Send the link to one person  
Send it in a direct message, not a public channel: whoever opens it first uses it. Avoid email and apps that preview links, because a scanner that runs the page could use its one opening. Don’t open it yourself to check it, for the same reason. Run qurl share again whenever you need a fresh link.

## What the recipient sees

The first open starts a session for the demo. Opening the same link again shows “Access link invalid” and asks for a new link.

## Which tools give a link that stops working on its own?

| Option                                                                                  | Choose it when                                                                                                                                      | Trade-off                                                                                                           |
| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| [qURL](https://layerv.ai/glossary/single-use-link/)                                     | qURL fits when a link should work once: qurl share links are single-use by default and expire within 24 hours, and --ttl shortens that.             | A qURL link cannot be reopened once used, so send a fresh one if the demo restarts, and your computer must stay on. |
| [Microsoft dev tunnels](https://layerv.ai/compare/qurl-vs-microsoft-dev-tunnels/)       | Microsoft dev tunnels fit when viewers can sign in with GitHub or Microsoft: anonymous access can be time-limited, and access tokens last 24 hours. | Microsoft dev tunnels show an anti-phishing page on the first visit, and you sign in to host one.                   |
| [Pinggy](https://layerv.ai/compare/qurl-vs-pinggy/)                                     | Pinggy fits a public demo that should end on its own: a free Pinggy tunnel times out after 60 minutes.                                              | A Pinggy URL is public until then: anyone who has it can open it, as often as they like.                            |
| [Cloudflare Quick Tunnels](https://layerv.ai/compare/qurl-vs-cloudflare-quick-tunnels/) | A Cloudflare Quick Tunnel fits when you will end the demo yourself: the URL stops working when cloudflared stops.                                   | A Cloudflare Quick Tunnel URL has no expiry or single-use setting, and it is public unless you set --allowed-mail.  |

## Troubleshooting

| If you see                                                                                                             | Do this                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| qurl publish says the local app is not accepting TCP connections                                                       | Start the app first and check that curl works on the same address. qurl publish connects to localhost as 127.0.0.1, so if your app listens only on IPv6 (on macOS or Linux, lsof -iTCP -sTCP:LISTEN -nP shows \[::1\]), publish 'http://\[::1\]:PORT' instead, or start the dev server with --host 127.0.0.1 and publish that address. Neither requires listening on your LAN. Keep the quotes: zsh treats the brackets as a pattern.                         |
| The recipient sees “Access link invalid”                                                                               | The link was already used or has expired. Run qurl share again and send the new link.                                                                                                                                                                                                                                                                                                                                                                         |
| The recipient sees “Resource not found”                                                                                | The resource was deleted after the link was made. Publish the app again, then run qurl share and send the new link.                                                                                                                                                                                                                                                                                                                                           |
| publish rejects http://127.0.0.1 with “only HTTPS URLs are allowed”, or asks you to log in                             | You have a CLI older than 3.0\. On macOS run brew update, then brew upgrade qurl; elsewhere install the latest release again. After updating, qurl --version should print 3.4.1 or later.                                                                                                                                                                                                                                                                     |
| publish prints no Access: line, or the Access: line says public and you did not ask for public                         | With no Access: line, the CLI is older than 3.4.1: on macOS run brew update, then brew upgrade qurl; elsewhere install the latest release again. A resource that an older CLI published is public unless you published it with --private, and anyone who has the CRID of a public resource can open it. To make a public resource private, run qurl delete <CRID> and publish again with qurl 3.4.1 or later. The new resource is private and has a new CRID. |
| publish says this Linux session “can’t reach a systemd user manager”                                                   | You are in a container or sandbox without a user service manager. Run qurl publish with --foreground; sharing lasts as long as that process runs.                                                                                                                                                                                                                                                                                                             |
| publish says “Quota Exceeded” with “protected resource limit reached”, or “Your qURL account has reached a plan limit” | You can see this without an account: a device with no account can keep up to 3 active resources, with links that last up to 24 hours. Run qurl list --status active, then qurl delete <CRID> for any you no longer need (it asks you to confirm; --yes skips that). qurl stop keeps the resource, so it does not free a slot.                                                                                                                                 |

## Frequently Asked Questions

Does single-use mean one page load? 

No. Single use limits how many times the link can be opened. The session it starts allows as many requests as the app makes until the session ends.

Can I make a link several people can use? 

Not with qurl share. It has no option for a reusable link, and links for apps published from the CLI are single-use by default. Run qurl share once per person instead, which also lets each link expire on its own. To let several people in without a link each, turn access requests on with qurl requests <CRID> --on (qurl 3.4.1 or later): each person asks at https://qurl.link/<CRID> and you approve them by the code they give you. Approve a code only when it came from the person you mean to let in, over a channel where you know it is them.

Who else can reach my app while the link is open? 

Opening the link admits the network address it was opened from for the session, which lasts 1 hour by default. Other devices that share that public IP address, such as people on the same office or café network or VPN, can reach the app until the session ends. By default a link admits whoever opens it; access rules set through the API, such as IP allow and deny lists, can restrict that. Keep your app’s own sign-in for anything sensitive.

## Related Resources

[Glossary: Single-use link →](https://layerv.ai/glossary/single-use-link/) [Guide: Give a contractor temporary access →](https://layerv.ai/guides/give-a-contractor-temporary-access/) [Guide: Revoke access to a shared app →](https://layerv.ai/guides/revoke-access-to-a-shared-app/) [Guide: Share a dev server with a client →](https://layerv.ai/guides/share-dev-server-with-client/) [Guide: Share localhost without signing up →](https://layerv.ai/guides/share-localhost-without-signup/) [Every localhost tunnel, compared →](https://layerv.ai/compare/localhost-tunnels/)

## Publish your app now

Install the CLI, then run one command. No sign-up, no API key.

[Install the CLI ↗](https://layerv.ai/cli/)



---

*This markdown version is auto-generated from [https://layerv.ai/guides/one-time-link-for-a-demo/](https://layerv.ai/guides/one-time-link-for-a-demo/) for AI agents. Curated agent resources: [llms.txt](https://layerv.ai/llms.txt). For the full interactive experience, visit the HTML version.*

