Custom Access Request Page
This feature is available in our custom plans. Please contact us to get access.
Introduction
Ever had users message you frantically because they can't access a dashboard? With custom 403 pages, you can turn that dead-end "Access Denied" screen into something actually useful.
Instead of users hitting a wall, you can:
- Send them to a request form - Link to Google Forms, Jotform, whatever you use
- Show who to contact - "Need the sales dashboard? Email [email protected]"
- Give them next steps - Link to your wiki, ticket system, or training docs
- Pre-fill their info - Their name, email, and the dashboard they need are already filled in
Common Use Cases
The "Request Access" Button
This is what most teams use. User can't see a dashboard? They click a button, fill out a form, done. You get notified and can approve it.
"Here's How to Get Access"
Some companies have specific processes - maybe you need to complete data training first, or submit a ticket through ServiceNow. Link directly to those resources so users can help themselves.
Quick Setup
- Go to Organization Settings → Custom 403 Page
- Grab one of the templates below (or write your own)
- Replace the example links with your actual form URLs
- Hit save
That's it. Next time someone hits a restricted dashboard, they'll see your custom message instead of a generic error.
Ready-to-Use Templates
Template 1: "Request Access" Button
- Preview
- HTML Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>403 - Access Forbidden</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
min-height: 100vh;
background: #f5f5f5;
color: #374151;
line-height: 1.5;
font-size: 14px;
}
.navbar {
background: #ffffff;
border-bottom: 1px solid #e5e7eb;
padding: 16px 24px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
}
.logo {
height: 32px;
width: auto;
}
.main-content {
display: flex;
align-items: center;
justify-content: center;
min-height: calc(100vh - 73px);
padding: 24px;
}
.container {
max-width: 520px;
width: 100%;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border: 1px solid #e5e7eb;
overflow: hidden;
}
/* Modal Header */
.modal-header {
padding: 24px 24px 20px 24px;
border-bottom: 1px solid #e5e7eb;
position: relative;
}
.error-title {
font-size: 18px;
font-weight: 500;
color: #111827;
margin-bottom: 8px;
}
.error-message {
color: #9ca3af;
font-size: 14px;
font-weight: 400;
line-height: 1.5;
}
/* Modal Body */
.modal-body {
padding: 24px;
}
.info-section {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 6px;
padding: 16px;
}
.info-title {
font-size: 14px;
font-weight: 500;
color: #111827;
margin-bottom: 12px;
}
.info-grid {
display: grid;
gap: 8px;
}
.info-item {
display: grid;
grid-template-columns: 70px 1fr;
gap: 12px;
font-size: 14px;
align-items: start;
}
.info-label {
color: #6b7280;
font-weight: 400;
text-align: left;
}
.info-value {
color: #111827;
word-break: break-all;
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
background: #ffffff;
padding: 4px 8px;
border-radius: 4px;
border: 1px solid #e5e7eb;
font-size: 13px;
}
/* Modal Footer */
.modal-footer {
padding: 16px 24px 24px 24px;
border-top: 1px solid #f3f4f6;
display: flex;
justify-content: flex-end;
gap: 8px;
}
.dashboard-button {
display: inline-flex;
align-items: center;
background: #ffffff;
color: #374151;
padding: 6px 12px;
border: 1px solid #d1d5db;
border-radius: 4px;
font-weight: 500;
font-size: 13px;
text-decoration: none;
transition: all 0.2s ease;
min-height: 28px;
cursor: pointer;
}
.dashboard-button:hover {
background: #f9fafb;
border-color: #9ca3af;
}
.request-button {
display: inline-flex;
align-items: center;
background: #3b82f6;
color: #ffffff;
padding: 6px 12px;
border: none;
border-radius: 4px;
font-weight: 500;
font-size: 13px;
text-decoration: none;
transition: all 0.2s ease;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
min-height: 28px;
}
.request-button:hover {
background: #2563eb;
}
@media (max-width: 640px) {
.navbar {
padding: 12px 16px;
}
.logo {
height: 28px;
}
.main-content {
padding: 16px;
}
.modal-header {
padding: 20px 20px 16px 20px;
}
.modal-body {
padding: 20px;
}
.modal-footer {
padding: 16px 20px 20px 20px;
flex-direction: column;
}
.error-title {
font-size: 16px;
}
.info-item {
grid-template-columns: 1fr;
gap: 4px;
}
.info-label {
font-size: 13px;
}
}
</style>
</head>
<body>
<nav class="navbar">
<img src="https://media.holistics.io/ef25c515-holistics-logo-colored.svg" alt="Holistics" class="logo">
</nav>
<div class="main-content">
<div class="container">
<!-- Modal Header -->
<div class="modal-header">
<h1 class="error-title">403 - Access Forbidden</h1>
<p class="error-message">
You don't have permission to access this resource. Please request access to continue.
</p>
</div>
<!-- Modal Body -->
<div class="modal-body">
<div class="info-section">
<h2 class="info-title">Request Details</h2>
<div class="info-grid">
<div class="info-item">
<span class="info-label">User:</span>
<span class="info-value">{{USER_NAME}}</span>
</div>
<div class="info-item">
<span class="info-label">Email:</span>
<span class="info-value">{{USER_EMAIL}}</span>
</div>
<div class="info-item">
<span class="info-label">Company:</span>
<span class="info-value">{{TENANT_NAME}}</span>
</div>
<div class="info-item">
<span class="info-label">Path:</span>
<span class="info-value">{{CURRENT_PATH}}</span>
</div>
<div class="info-item">
<span class="info-label">Host:</span>
<span class="info-value">{{CURRENT_HOST}}</span>
</div>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<a href="/dashboards" target="_top" class="dashboard-button">
Back to Dashboard
</a>
<a href="" target="_top" class="request-button">
Request Access
</a>
</div>
</div>
</div>
</body>
</html>

Remember to replace the link in the Request Access button with the link to your form
<a href="link-to-your-form" target="_top" class="request-button">
Request Access
</a>
Template 2: Connecting to Form Services
Want to pre-fill the user's info in your form? Here's how to set that up with different services:
Google Forms
<!-- Create your form with these fields: Email, Name, Dashboard URL, Reason -->
<!-- Get the prefilled link from Forms > More > Get pre-filled link -->
<a href="https://forms.gle/YOUR_FORM_ID?entry.emailFieldId={{ USER_EMAIL }}&entry.nameFieldId={{ USER_NAME }}&entry.urlFieldId={{ CURRENT_URL }}"
target="_top"
style="background: #4285f4; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
Request via Google Forms
</a>
Jotform
<!-- Jotform accepts URL parameters for field prefilling -->
<a href="https://form.jotform.com/YOUR_FORM_ID?email={{ USER_EMAIL }}&name={{ USER_NAME }}&dashboard={{ CURRENT_PATH }}"
target="_top"
style="background: #FF6100; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
Request via Jotform
</a>
Microsoft Forms
<!-- For Office 365 users -->
<a href="https://forms.office.com/r/YOUR_FORM_ID?email={{ USER_EMAIL }}&name={{ USER_NAME }}"
target="_top"
style="background: #0078d4; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
Request via Microsoft Forms
</a>
Typeform
<!-- Typeform uses # for hidden fields -->
<a href="https://yourcompany.typeform.com/to/YOUR_FORM_ID#email={{ USER_EMAIL }}&name={{ USER_NAME }}&dashboard={{ CURRENT_URL }}"
target="_top"
style="background: #262627; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
Request via Typeform
</a>
Variables You Can Use
These automatically fill in with the user's actual info:
Variable | Description | Example Output |
---|---|---|
{{ USER_NAME }} | User's display name | "Jane Smith" |
{{ USER_EMAIL }} | User's email | "[email protected]" |
{{ TENANT_NAME }} | Your organization | "Acme Corp" |
{{ CURRENT_PATH }} | Dashboard path | "/dashboards/sales-metrics" |
{{ CURRENT_URL }} | Full URL attempted | "https://app.holistics.io/dashboards/123" |
{{ CURRENT_HOST }} | Domain name | "app.holistics.io" |
Heads up: URL Encoding
Some form services get confused by special characters in URLs. If your form isn't pre-filling correctly, try URL encoding:
<!-- Some form services need encoded URLs -->
<a href="https://forms.gle/abc123?dashboard={{ CURRENT_URL | urlencode }}" target="_top">
Request Access
</a>
What Works (and What Doesn't)
You can use:
- HTML and CSS (inline or in
<style>
tags) - Links to anywhere (just add
target="_top"
) - All the variables listed above
You can't use:
- External JavaScript sources or inline scripts (security limitations)
- External CSS links or files
- Form inputs or buttons (links only)
Important: All links must include target="_top"
to navigate properly:
<!-- Correct -->
<a href="https://forms.gle/abc123" target="_top">Request Access</a>
<!-- Won't work -->
<a href="https://forms.gle/abc123">Request Access</a>