Pibicut

Frappe/ERPNext URL Shortener with QR Code Generator

Install Pibicut

bench get-app https://github.com/pibico/pibicut

Add the Frappe Gems badge to your README

Maintain Pibicut? Paste this into your README:

[![Listed on Frappe Gems](https://frappegems.com/api/method/frappe_gems.seo.badge?app=pibico%2Fpibicut)](https://frappegems.com/gems/apps/pibico/pibicut)

About Pibicut

PibiCut

URL Shortener and QR Code Generator for Frappe/ERPNext

Version Frappe License

PibiCut is a simple Frappe App to create shortened URLs and generate QR codes. When users access a short URL (e.g., https://yoursite.com/MnOpQ), they are automatically redirected to the original long URL. The QR code can also be scanned to access the short URL.


Table of Contents


Features

Core Capabilities

  • URL Shortening - Convert long URLs into 5-character short codes
  • Custom Short Codes - Define your own memorable short codes (3-20 chars)
  • Custom Code Rename - Change custom codes on existing URLs (auto-rename)
  • QR Code Generation - Automatic styled QR code creation for each short URL
  • QR Code Sizes - Choose Small, Medium, or Large QR code output
  • Custom Logo Support - Embed your logo in the center of QR codes
  • Click Analytics - Track click count and last clicked timestamp
  • Link Expiration - Set optional expiration dates for time-limited links
  • Instant Redirect - Short URLs redirect immediately to target destinations
  • UPI Support - Works with UPI payment links in addition to HTTP/HTTPS URLs
  • Guest Access - Short URLs work without authentication (public redirect pages)
  • Bulk Export - Export multiple QR codes as a ZIP file

QR Code Features

Feature Description
Styled Design Radial gradient (steelblue → black) with gapped squares
Size Options Small, Medium, Large output sizes
Embedded Logo Optional PNG image in the center of QR code
Error Correction Uses ERRORCORRECTH level for reliable logo embedding
Base64 Storage QR codes stored as data URLs (no separate files)
Instant Preview Live QR code preview in the form
Download Button One-click download as PNG file

Limitations

  • Short codes are 5 random characters (or custom 3-20 chars)
  • Logo images must be PNG format with white background (not transparent)
  • Custom codes: letters, numbers, and hyphens only

Version Compatibility

Frappe Version PibiCut Branch Status Notes
v15 version-15 Active Development Recommended for new installations
v14 version-14 Stable Production ready
v13 version-13 Stable Production ready
v12 version-12 Legacy No longer maintained

Requirements

System Requirements

  • Frappe/ERPNext: v12, v13, v14, or v15
  • Python: 3.10+ (included with Frappe v15)

Python Dependencies

qrcode>=7.0.0
pillow>=9.0.0
six>=1.16.0

These are automatically installed via pyproject.toml.


Installation

Standard Installation

# Navigate to your frappe-bench directory
cd ~/frappe-bench

# Download the app
bench get-app pibicut https://github.com/pibico/pibicut.git

# Install on your site
bench --site your-site-name install-app pibicut

# Restart bench to apply changes
bench restart

Multi-tenant Installation

bench --site site_name install-app pibicut

Updating

# Update the app
cd ~/frappe-bench
bench update

# If you encounter dependency issues
bench update --requirements

# Restart
bench restart

Uninstalling

bench --site your-site-name uninstall-app pibicut
bench remove-app pibicut

Configuration

No configuration required! PibiCut works out of the box after installation.

Permissions

By default, the Shortener DocType has the following permissions:

Role Create Read Write Delete Export Print
System Manager Yes Yes Yes Yes Yes Yes
All Yes Yes Yes No Yes Yes

To modify permissions, navigate to Shortener > Settings > Role Permissions Manager.


Usage

Creating a Short URL

  1. Navigate to Shortener in the sidebar or search bar
  2. Click + Add Shortener (or New)
  3. Enter the Long URL (must start with http://, https://, or upi:)
  4. (Optional) Enter a Custom Short Code (3-20 chars, letters/numbers/hyphens)
  5. (Optional) Set Expires On date for time-limited links
  6. (Optional) Select QR Code Size (Small/Medium/Large)
  7. (Optional) Attach a Logo image (PNG with white background)
  8. Click Save

Result

After saving, you will get:

  • Short URL: https://yoursite.com/MnOpQ (random) or https://yoursite.com/your-code (custom)
  • QR Code: Styled QR code image with optional logo
  • Copy Button: One-click copy of short URL to clipboard
  • Download Button: Download QR code as PNG
  • Web Page: Accessing the short URL redirects to the long URL

Changing Custom Code (Existing URLs)

You can change the custom code of an existing short URL:

  1. Open the existing Shortener document
  2. Enter a new Custom Short Code
  3. Click Save
  4. Document is renamed, QR code regenerated with logo preserved
  5. Browser automatically redirects to the new URL

Sharing the Short URL

You can share the short URL in two ways:

  1. Direct Link: Copy the short URL and share it
  2. QR Code: Download or print the QR code for scanning

Example

Field Value
Long URL https://example.com/very/long/path/to/page?param1=value1¶m2=value2
Short URL https://yoursite.com/xK9Pb
Redirect Accessing https://yoursite.com/xK9Pb goes to the long URL

Architecture

System Overview

┌─────────────────────────────────────────────────────────┐
│                    PibiCut Flow                          │
├─────────────────────────────────────────────────────────┤
│                                                           │
│  User creates Shortener doc                               │
│            ↓                                              │
│  ┌──────────────────────────────────────────────────┐    │
│  │ autoname()                                        │    │
│  │ - Generates 5-char random code (e.g., "MnOpQ")   │    │
│  │ - Checks for uniqueness                           │    │
│  └──────────────────────────────────────────────────┘    │
│            ↓                                              │
│  ┌──────────────────────────────────────────────────┐    │
│  │ before_save()                                     │    │
│  │ - Sets route = short code                         │    │
│  │ - Generates QR code with optional logo            │    │
│  │ - Sets published = True for WebsiteGenerator      │    │
│  └──────────────────────────────────────────────────┘    │
│            ↓                                              │
│  Document saved with short URL and QR code               │
│                                                           │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│                    Redirect Flow                          │
├─────────────────────────────────────────────────────────┤
│                                                           │
│  User visits: https://yoursite.com/MnOpQ                 │
│            ↓                                              │
│  ┌──────────────────────────────────────────────────┐    │
│  │ WebsiteGenerator serves shortener.html template  │    │
│  │ - JavaScript: window.location.replace(long_url)  │    │
│  │ - HTML fallback: Link to long_url                │    │
│  └──────────────────────────────────────────────────┘    │
│            ↓                                              │
│  Browser redirects to: https://example.com/long/url      │
│                                                           │
└─────────────────────────────────────────────────────────┘

Key Components

WebsiteGenerator

The Shortener DocType extends WebsiteGenerator, which enables:

  • Public web pages without authentication
  • Custom routes based on document fields
  • Template-based rendering

QR Code Generation

QR codes are generated using:

  • qrcode library with StyledPilImage
  • Radial gradient color mask (steelblue center → black edges)
  • Gapped square module drawer for modern look
  • Optional logo embedding with PIL

Code Structure

Directory Layout

pibicut/
├── pibicut/
│   ├── __init__.py
│   ├── hooks.py                 # Frappe integration hooks
│   └── pibicut/
│       ├── __init__.py
│       ├── custom.py            # QR code generation (get_qrcode)
│       └── doctype/
│           └── shortener/
│               ├── __init__.py
│               ├── shortener.json      # DocType schema
│               ├── shortener.py        # Server controller
│               ├── shortener.js        # Client form script
│               ├── shortener_list.js   # List view config
│               ├── test_shortener.py   # Test file
│               └── templates/
│                   ├── shortener.html      # Redirect template
│                   └── shortener_row.html  # List row template
├── pyproject.toml              # Python dependencies
├── README.md                   # This file
├── CLAUDE.md                   # AI assistant context
└── license.txt                 # MIT License

Key Files

pibicut/hooks.py

Purpose: Defines app metadata and Frappe integration

app_name = "pibicut"
app_title = "Pibicut"
app_publisher = "PibiCo"
app_description = "Frappe/ERPNext URL Shortener"
app_license = "MIT"

pibicut/pibicut/custom.py

Purpose: QR code generation logic

def get_qrcode(input_data, logo):
    """
    Generate a styled QR code with optional embedded logo.

    Args:
        input_data: The URL to encode
        logo: Path to logo image (PNG) or None

    Returns:
        Base64-encoded data URL of the QR code PNG
    """

Features: - Radial gradient color mask (steelblue → black) - Gapped square module drawer - Square eye drawer - Optional logo embedding - Returns base64 data URL

pibicut/pibicut/doctype/shortener/shortener.py

Purpose: Server-side controller for Shortener DocType

Key Methods:

Method Purpose
autoname() Use custom_code or generate random 5-char code (new docs)
_validate_custom_code() Validate custom code format and availability
short_url Property returning full short URL
validate() Validate URL format (http/https/upi)
before_save() Generate QR code with logo and set route
on_update() Rename document if custom_code changed (existing docs)
get_context() Handle redirect with click tracking and expiration

Code Flow:

```python class Shortener(WebsiteGenerator): def autoname(self): # For NEW documents if self.customcode: self.validatecustomcode(self.customcode) self.name = self.customcode else: randomcode = randomstring(5) while frappe.db.exists("Shortener", randomcode): randomcode = randomstring(5) self.name = randomcode

def on_update(self):
    # For EXISTING documents - rename if custom_

Related Developer Tools apps for Frappe & ERPNext

  • Frappe — Low code web framework for real world applications, in Python and Javascript
  • Frappe Docker — Docker environment for developing, deploying, and running Frappe applications (ERPNext and custom apps) in production and development
  • Builder — Craft beautiful websites effortlessly with an intuitive visual builder and publish them instantly
  • Bench — CLI to manage Multi-tenant deployments for Frappe apps
  • Frappe Ui — A set of components and utilities for rapid UI development
  • Press — Full service cloud hosting for the Frappe stack - powers Frappe Cloud
  • Gameplan — Open Source Discussions Platform for Remote Teams
  • Doppio — A Frappe app (CLI) to magically setup single page applications and Vue/React powered desk pages on your custom Frappe apps.