Skip to main content
You can add your own logic to this CRM — send a Slack message when a lead converts, sync invoices to your accounting system, tweak a PDF template — without editing any core file. That means your changes survive every future update: you just drop your code into one file, and updates never touch it.

Where your code goes

Everything lives in app/Hooks/custom.php. It ships blank. Add functions and register them with add_action() or add_filter(), the same pattern used by WordPress and Perfex — if you’ve customized either of those before, this will feel familiar.
If your callback throws an exception, it’s caught and logged — it will never break the action that triggered it (a broken Slack integration won’t stop a real lead from converting).

Actions — do something after an event

Filters — change a value

Filters let you swap out a value the app is about to use. Return your own value from the callback:
A worked example: put your own Blade file at resources/views/pdfs/invoice-eu.blade.php and use it only for EUR customers, without ever touching the stock pdfs/invoice.blade.php.
The screens you see in the browser (Kanban board, dashboard, reports, everything) are a compiled React app, not server-rendered Blade — there’s no template-override mechanism for them the way there is for PDFs. You have the full resources/js/ source in your copy, so you’re always free to edit a page directly; there just isn’t a drop-in-override layer for it like custom.php gives you for backend logic. If you do edit resources/js/, run npm run build afterward and keep a note of what you changed before installing a future update.

Text and translations

Every user-facing string in Laravel’s own auth screens (login, password reset, etc.) can be overridden without touching a template, via lang/en/*.php. If those files don’t exist yet in your copy, generate them with:
Laravel checks your lang/ directory first, so anything you put there wins.