diff --git a/README.md b/README.md
index 5f01c1d..cc7127a 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,32 @@ installed on the jupyter server, and use the proxied data server transformer:
alt.data_transformers.enable('data_server_proxied')
```
+The `urlpath` parameter allows you to override the prefix of the proxy URL. By
+default, it's set to `..`, which is currently the only way to make it work for
+arbitrary users when running inside the classic notebook on Binder. If you
+intend your notebooks to be run on Binder but inside JupyterLab, change it to
+`.` instead, which will work provided JupyterLab is in the [default
+workspace](https://jupyterlab.readthedocs.io/en/stable/user/urls.html#managing-workspaces-ui).
+
+```python
+# for notebooks intended for JupyterLab on Binder
+alt.data_transformers.enable('data_server_proxied', urlpath='.')
+```
+
+On a custom JupyterHub instance, a much more robust option is to take advantage
+of JupyterHub's [`/user-redirect`](https://jupyterhub.readthedocs.io/en/stable/reference/urls.html#user-redirect)
+feature (which is not available on Binder):
+
+```python
+# this will work for any JupyterHub user, whether they're using the classic
+# notebook, JupyterLab in the default workspace, or JupyterLab in a named
+# workspace
+alt.data_transformers.enable('data_server_proxied', urlpath='/user-redirect')
+```
+
+If your JupyterHub lives somewhere else than at your server's root, add the
+appropriate prefix to `urlpath`.
+
## Example
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/altair-viz/altair_data_server/master?urlpath=lab/tree/AltairDataServer.ipynb)
diff --git a/altair_data_server/_altair_server.py b/altair_data_server/_altair_server.py
index b488bd3..94de99c 100644
--- a/altair_data_server/_altair_server.py
+++ b/altair_data_server/_altair_server.py
@@ -56,13 +56,18 @@ def __call__(
class AltairDataServerProxied(AltairDataServer):
def __call__(
- self, data: pd.DataFrame, fmt: str = "json", port: Optional[int] = None
+ self,
+ data: pd.DataFrame,
+ fmt: str = "json",
+ port: Optional[int] = None,
+ urlpath: str = "..",
) -> Dict[str, str]:
result = super().__call__(data, fmt=fmt, port=port)
url_parts = parse.urlparse(result["url"])
+ urlpath = urlpath.rstrip("/")
# vega defaults to /files, redirect it to /proxy//
- result["url"] = f"../proxy/{url_parts.port}{url_parts.path}"
+ result["url"] = f"{urlpath}/proxy/{url_parts.port}{url_parts.path}"
return result