Introduction: What Are Portal Pages in Frappe?
Portal pages in Frappe Framework v15 are website-accessible pages designed for external users such as customers, suppliers, or members. These pages are served through the Website module and rendered using HTML and Jinja templates.
Portal pages allow businesses to expose ERP data securely without giving Desk access.
Technical Scope & Prerequisites
Applies To
- Frappe Framework v15
- Website Module
- Portal Development
Prerequisites
Working Frappe site
Website module enabled
Access to app /www directory
How Do You Add a Portal Page in Frappe v15?
Answer:
Portal pages are added by creating files inside the /www directory of a Frappe app.
Each file automatically becomes a public or portal-accessible route.
Adding a Simple Portal Page (Step-by-Step)
Step 1: Create a Page File
Inside your custom app:
your_app/www/my-page.html
This automatically creates the route:
/my-page
Step 2: Add Page Content
{% extends "templates/web.html" %}
{% block page_content %}
<h1>My Portal Page</h1>
<p>Welcome to the portal.</p>
{% endblock %}
This uses the standard Frappe website layout.
How Routing Works for Portal Pages
Frappe maps routes directly from file paths:
| File Path | URL Route |
| www/index.html | / |
| www/orders.html | /orders |
| www/orders/index.html | /orders |
| www/orders/details.html | /orders/details |
Key Rule:
Folder structure = URL hierarchy.
Making a Page Available Only to Logged-In Users
Use the login_required flag in Python context.
Example (my-page.py)
def get_context(context):
context.login_required = True
This ensures:
- Only authenticated users can access the page
- Anonymous users are redirected to login
Using Python Context Files with Portal Pages
Each portal page can have a matching Python file.
Example:
my-page.html
my-page.py
def get_context(context):
context.title = "My Portal Page"
This allows:
- Dynamic data rendering
- Permission checks
- Context-based logic
Displaying ERP Data on Portal Pages
Portal pages can safely display ERP data using server-side logic.
Example
def get_context(context):
context.orders = frappe.get_all(
"Sales Order",
filters={"customer": frappe.session.user},
fields=["name", "status", "grand_total"]
)
This follows Frappe v15 ORM rules and permission checks.
Adding Portal Pages to Navigation Menus
Portal pages do not automatically appear in menus.
You must explicitly add them via:
- Website Settings → Top Bar
- Or portal_menu_items in hooks
portal_menu_items = [
{"title": "My Page", "route": "/my-page"}
]
Best Practices for Adding Portal Pages
- Use clear, readable route names
- Always extend templates/web.html
- Separate logic into .py files
- Avoid direct database queries in templates
- Apply permission checks early
Common Mistakes to Avoid
- Creating pages outside /www
- Embedding business logic in HTML
- Forgetting login_required for sensitive pages
- Using Desk-only APIs in portal pages
Real-World Use Case
Customer Self-Service Portal
- /orders → Order list
- /orders/details → Order detail view
- /invoices → Download invoices
This reduces support load and improves customer experience.
Troubleshooting Portal Page Issues
Page not loading
- Check file path and naming
- Clear website cache
Permission denied
- Verify login_required
- Confirm user roles
Data not rendering
- Validate Python context file
- Check ORM filters
Cross-References
Official Docs – Adding Pages
https://docs.frappe.io/framework/user/en/guides/portal-development/adding-pages
Frappe v15 Source
https://github.com/frappe/frappe/tree/version-15
Industry Relevance
- ERPNext Customer Portals
- Supplier Dashboards
- Membership & Subscription Systems
- Service Request Portals
Conclusion
Adding portal pages in Frappe Framework v15 is intentionally simple and file-driven. By using the /www directory, Python context files, and built-in routing, developers can quickly build secure, scalable portal experiences.