A practical, field-tested workflow for scoping, prompting, building, uploading and testing HubSpot custom quote modules with ChatGPT, Codex and the HubSpot CLI.
HubSpot's standard quote modules are enough for many businesses. But quoting becomes harder when buyers need to see products and services grouped in a particular way, different terms must appear under different conditions, or the quote needs to reflect a commercial model that does not fit a standard line item table.
That is where custom-coded quote modules become useful.
HubSpot now supports custom React-based modules that can sit alongside its standard quote modules. You can change a specific part of the quote experience without rebuilding the entire quote as a legacy custom template. The underlying quote, deal and line item data can remain in HubSpot, while the custom module controls how selected information is presented. HubSpot's overview includes examples such as grouped line items, optional items, billing schedules, conditional terms, navigation, bespoke styling and mandatory buyer acknowledgements.
We recently used this approach on a real Growth London client delivery. The client needed a clearer way to present different categories of line items to buyers. We built a module that grouped line items using a Product Type property, hid empty sections, added section subtotals, displayed a discount column only when discounts existed, supported different language labels and preserved HubSpot's native line item editing.
The code mattered, but it was not the hardest or most important part of the job.
The first mistake is to think of this as a coding project. It is really a requirements translation project. You are translating the way a business sells into a quote module that HubSpot can render, sales users can manage and buyers can understand.
The biggest unlock is not simply that Codex can write a React module. It is that a consultant can now move from client call notes to an approved quote-module brief and then to a working HubSpot module in one controlled workflow.
Before looking at the build process, it helps to understand the range of problems a custom module can solve.
A custom module can:
Modules can also display content according to quote, buyer or product data. For example:
Other useful applications include:
The same module can support:
A HubSpot quote is a web-based sales document, not just a PDF. Custom modules can add richer proposal elements such as:
There is an important boundary here. A custom module should usually improve the quote experience. It should not quietly become a shadow CPQ or pricing engine unless that has been deliberately designed, scoped and governed.
Our repeatable process is:
quote-dev-starter, Codex and HubSpot CLI authentication.The division of labour is simple:
| Environment | Primary role |
|---|---|
| ChatGPT client thread | Client context, requirements analysis, scoping, prompt design and QA decisions |
| Codex project | Repository inspection, code changes, local checks and CLI commands |
| HubSpot | Quote data, template configuration, project builds and real-output testing |
Start with the quote problem, not the technical solution.
Useful source material may include:
At this stage, separate four things that are often blurred together:
That distinction prevents a display module from accidentally taking responsibility for pricing or automation.
We are scoping a custom-coded HubSpot quote module for a client.
Review the call notes, screenshots, current quote examples and email requirements in this thread. Produce a client-facing Custom Quote Module Brief.
Include:
1. Background and desired buyer experience
2. Current quote-template limitations
3. Required custom modules
4. Required quote, line item, product or associated-object properties
5. Required display logic
6. Conditional behaviour
7. User-editable module fields
8. Language or regional requirements
9. What remains native HubSpot functionality
10. Explicit out-of-scope items
11. Acceptance criteria
12. Questions to confirm with the client
Important:
- Do not invent requirements that are not supported by the source material.
- Do not assume the module should change quote totals unless this is explicitly required.
- Separate display requirements from pricing, automation and data requirements.
- State what sales users will continue to manage through native HubSpot quote line items.
- Flag any unknown property names or unclear calculation rules for confirmation.
Write this as a concise consulting brief that can be shared with the client for approval.
The approved brief is the control point between discovery and development.
It should answer questions such as:
Client approval is valuable even on a small build. It stops design preferences and new commercial logic being introduced halfway through development as if they were corrections.
The client has approved the Custom Quote Module Brief above and supplied the clarifications below.
[Insert the final clarifications.]
Convert the approved brief into a build-ready technical specification for Codex.
Include:
- module name and purpose;
- user-editable fields in the module editor;
- exact quote, line item, product or associated-object properties required;
- display rules;
- grouping and sorting rules;
- calculation rules, including rounding and currency treatment;
- conditional behaviour;
- fallback behaviour for missing or unexpected data;
- editor and quote-blueprint behaviour;
- temporary debug behaviour;
- test scenarios;
- accessibility and print/PDF considerations;
- non-goals; and
- deployment assumptions.
Where an internal HubSpot property name has not been confirmed, mark it as an unresolved dependency. Do not invent one.
Keep the specification implementation-focused but readable by a HubSpot consultant.
For this kind of work, the plumbing is a meaningful part of the delivery. Codex needs a correctly structured local project, the HubSpot CLI needs to be authenticated to the right account, and the project needs to reach the client's portal safely.
At the time of writing, HubSpot requires Revenue Hub Professional or Enterprise for custom quote modules. Its build guide also says that quote-module projects cannot currently be created through the normal CLI project-creation flow. Instead, start with HubSpot's official quote-dev-starter project.
quote-dev-starter into that folder.Typical commands are:
npm install
hs account auth
hs account list
hs account link
You can also set a default account explicitly:
hs account use <account-name-or-id>
HubSpot's current account command documentation recommends hs account link when different project directories target different accounts. The link is stored in the project's local .hs/settings.json file. This is particularly useful for a consultancy working across multiple client portals because it reduces the chance of running a command against the wrong account.
Even with a linked or default account, we prefer to make the target explicit when uploading:
hs project upload --account=<account-id-or-name> --debug
The first upload is different from later uploads. HubSpot will ask you to name and create the project, then build and normally auto-deploy it. HubSpot's project command documentation confirms that hs project upload creates a build and prompts to create the project if it does not yet exist.
Interactive prompts can trip up an otherwise automated Codex workflow. On the first upload, either complete the prompt yourself or tell Codex to stop and report any request for confirmation. Do not let an agent retry the same failed upload repeatedly without checking whether the project exists and whether human confirmation is required.
Inspect this HubSpot quote-dev-starter project and confirm whether it is ready for custom quote module development.
Do not build or change a module yet.
Use safe read-only checks to inspect:
- package installation state;
- project structure;
- hsproject.json;
- the relevant package.json files and available scripts;
- HubSpot CLI availability and version;
- authenticated HubSpot accounts;
- the account linked to this directory, if any;
- the current or default HubSpot account;
- whether this project already exists in the target HubSpot account; and
- whether the first upload is likely to trigger an interactive project-creation prompt.
Do not expose or print access keys, tokens or other secrets.
After checking, report:
1. The target account you believe this directory is connected to.
2. Any missing or ambiguous setup.
3. The exact validation and upload commands you recommend.
4. Any step that needs human confirmation before you continue.
5. Any assumptions that must be resolved before development begins.
The effective workflow was not to ask Codex to infer the whole solution from a sentence or two.
We kept the client delivery context in a dedicated ChatGPT thread. That thread held the call notes, screenshots, decisions, approved brief and client feedback. We then used it to write a focused prompt for Codex.
Codex worked inside the project repository. It could inspect the starter project, edit the relevant files, run TypeScript and formatting checks, review the diff and use the HubSpot CLI.
In practice, the loop looked like this:
This separation gives each environment a clear job. ChatGPT owns context and judgement. Codex owns the repository and execution. HubSpot remains the source system and test environment.
It also makes the process easier to audit. The approved brief explains what should be built, the Codex prompt explains the requested change, and the repository diff shows what actually changed.
Do not ask Codex to build the entire quote experience in one prompt.
Start with one module that has a clear source of truth and a testable output. Build it, upload it and test it before adding a dependent summary, conditional terms block or interactive acknowledgement.
In our anonymised client example, the first module was a grouped line item table.
The standard table was accurate but commercially flat. Buyers needed to understand which items belonged to different parts of the offer. The custom module:
That final point matters. If a custom module replaces the visible line item table, HubSpot says the standard Line items module must be hidden rather than removed. The standard module remains the mechanism through which users add, edit and remove the underlying line items. The custom module displays the data. It does not replace the native editing process.
Build Module 1 only: Grouped Line Items.
First inspect the quote-dev-starter patterns and the approved technical specification in this repository. If the brief conflicts with the current HubSpot starter or an exact property name is unresolved, stop and report the conflict rather than inventing an implementation.
Purpose:
Create a display-only HubSpot quote module that presents quote line items in sections based on the client's Product Type property.
Do not:
- create, edit or remove HubSpot line items;
- change quote totals or deal amounts;
- introduce a second module;
- hard-code prices;
- remove the requirement for HubSpot's native Line items module; or
- pass the full quoteTemplateContext or one of its full sub-objects into client-side props.
Implementation requirements:
- Follow the current quote-dev-starter custom quote module pattern.
- Export Component, fields, meta and hublDataTemplate as required by the starter.
- Support both QUOTE and QUOTE_BLUEPRINT content types.
- Use hublDataTemplate to extract only the fields required by this module.
- Reuse existing types and project conventions where possible.
- Provide sensible blueprint/editor fallback data.
- Keep presentation accessible and suitable for print/PDF.
Required line item data:
- SKU;
- product name;
- quantity;
- unit price;
- discount value or percentage, according to the approved brief;
- net line value;
- Product Type internal value; and
- quote currency.
Display rules:
- Group line items by the confirmed Product Type internal value.
- Use the approved group order and labels.
- Hide empty groups.
- Display a configurable heading above the module.
- Show SKU, product, quantity, unit price and net price.
- Show a subtotal for each group.
- Show the discount column only when at least one line item has a genuine discount.
- Show any total-discount summary only when a genuine discount exists.
- Use consistent column widths across every group.
- Allow product names to wrap naturally.
- Right-align numeric columns.
- Handle missing or unexpected Product Type values defensively.
Configuration fields:
- show or hide module heading;
- heading label;
- approved language or label set;
- editable display label for each group; and
- temporary debug-unmapped-items toggle.
Debug behaviour:
When enabled, show unmapped line items and the Product Type value detected for each one. Make the debug output visually distinct and easy to disable before go-live.
Test scenarios:
- quote template or blueprint view;
- draft quote preview;
- published quote;
- print/PDF output;
- no-discount quote;
- discounted quote;
- one populated group;
- multiple populated groups;
- missing Product Type;
- zero quantity or zero-value edge cases, if HubSpot permits them; and
- alternative language labels where internal Product Type values remain stable.
Before editing, summarise your intended file changes.
After implementation:
1. Summarise files created or changed.
2. List every assumed HubSpot property name.
3. Run the repository's existing type, lint, test and formatting scripts where available.
4. Run git diff --check.
5. Show a concise diff summary.
6. Do not upload until the local checks pass.
7. If local checks pass, report that the project is ready for upload and provide the exact command.
Notice what this prompt does not do. It does not tell Codex to invent field names, rewrite unrelated parts of the starter or build several modules at once. It defines the module boundary, data boundary, safety constraints and test scenarios.
HubSpot's starter uses hublDataTemplate to prepare specific server-side data for the React component. This is also a security boundary. HubSpot warns that passing the full quoteTemplateContext, or a full sub-object such as the quote, into an island exposes all of those properties in the published page source. Extract only the values the module genuinely needs.
Once the local checks pass, upload the project to the named account.
hs project upload --account=<account-id-or-name> --debug
Using the account flag is a useful last line of defence when you work with more than one client account. The account link, current directory and explicit upload target should all agree.
Prepare and upload the current HubSpot quote module project to the intended client account.
Before uploading:
1. Confirm the current directory contains hsproject.json.
2. Run hs account list.
3. Confirm the directory-linked account, if present.
4. Confirm the intended account ID/name matches the approved deployment target.
5. Run the repository's available type, lint, test and formatting checks.
6. Run git diff --check.
7. Stop if the account target is ambiguous or any local check fails.
Then run:
hs project upload --account=<account-id-or-name> --debug
Important:
- Do not print authentication secrets.
- If HubSpot asks to name or create the project, stop and report the exact prompt so a human can confirm it.
- Do not retry a failed upload until you have diagnosed the failure.
- Do not use force flags to bypass warnings.
After upload, report:
- whether the upload succeeded;
- the project and build identifier shown by HubSpot;
- whether the build deployed automatically;
- any warnings or errors;
- the project activity URL, if the CLI returned one; and
- the next manual step in HubSpot.
The first successful upload is a useful milestone. Once the project exists and its build has deployed, later uploads are normally more straightforward.
Do not add an untested module to the live template used by the sales team.
Instead:
Create a practical QA checklist for the approved Grouped Line Items custom quote module.
Use the approved brief, technical specification and acceptance criteria in this thread.
Organise the checklist into:
1. Project build and deployment checks
2. Cloned quote-template checks
3. Native Line items module checks
4. Draft quote and editor checks
5. Preview checks
6. Published quote checks
7. Print/PDF checks
8. Data and calculation checks
9. Language and regional checks
10. Client acceptance checks
Include scenarios for:
- no discounts;
- one discounted item;
- several discounted items;
- one Product Type group;
- several Product Type groups;
- an empty group;
- a missing or unexpected Product Type value;
- long product names and SKUs;
- different quantities and currencies where supported;
- alternative language labels;
- the hidden but retained native Line items module; and
- disabling all debug output before go-live.
For each test, provide:
- setup/data required;
- expected result;
- where to test it: editor, preview, published quote or PDF;
- pass/fail field; and
- notes/evidence field.
Do not invent expected calculations. Use only the rules in the approved specification and flag any gap.
Real published output matters. A table that looks right in the template editor may wrap differently in a browser or PDF. Interactive behaviour may need a static print treatment. Long labels can move columns. A zero discount can still create an unwanted empty column if the condition is too loose.
There is another important deployment detail: HubSpot says quotes are rendered when they are published. A newly deployed module version affects future quotes and unpublished drafts, but not quotes that have already been published. That is useful for stability, but it means you must publish a new test quote when validating a new build rather than relying on an older published URL.
Our first module worked functionally, but real quote testing exposed the details that made it client-ready:
That is the right order of work:
Keep each iteration narrow. A presentation refinement should not quietly rewrite calculation or grouping logic.
The Grouped Line Items module is functionally correct and has passed its data tests. Make a presentation-only refinement to this module.
Observed issues from the latest test quote:
- grouped tables use inconsistent column widths;
- the module needs a clearer heading;
- long product names need more natural wrapping; and
- numeric values should align consistently.
Requirements:
- add or refine the configurable module heading;
- use consistent column widths across every populated group;
- right-align quantity and monetary columns;
- let product names wrap naturally without breaking the table;
- make long SKUs wrap or truncate according to the approved design;
- preserve current grouping, ordering and subtotal logic;
- preserve discount visibility logic;
- preserve Product Type mapping;
- preserve language-label behaviour;
- preserve print/PDF support; and
- do not add another module or change any commercial calculation.
Before changing code, identify the files and styles you expect to touch.
After the change:
1. Summarise files changed.
2. Explain why the changes cannot alter calculations.
3. Run the existing local checks and git diff --check.
4. Provide a concise diff summary.
5. If all checks pass, upload to the explicit client account.
6. Report the new build/deployment result and the exact visual scenarios to retest.
Once the first module has a reliable data extraction pattern, tested layout and repeatable deployment process, you can add more complex modules.
Examples might include:
The key principle is to preserve the source of truth.
If a value affects what the client is charging, it should normally come from the Product Library and actual quote line items, or from another deliberately governed commercial system. Avoid hard-coding prices into a presentation module simply because it is technically possible.
For summary modules, a sensible priority order is often:
The correct order depends on the client's approved rules. The important point is to define it before Codex builds it.
The final deliverable should not just be working code.
Capture:
This turns a successful one-off delivery into a repeatable consulting method.
It also makes future work safer. A later developer or consultant can see why the module exists, which data it expects, what it must not change and how to test it before deployment.
Call notes and screenshots are not a build specification. Translate them into an approved brief first.
One module, one purpose and one acceptance test creates a much more reliable loop.
When a custom module replaces the visible line item table, hide the standard HubSpot module rather than removing it. Native editing still depends on it.
Do not pass the full quote context into a client-side island. Apart from making the implementation harder to reason about, it can expose unnecessary quote and associated-record properties in the published source.
Let governed Product Library and quote line item data own pricing wherever possible.
Link the client project directory to the correct HubSpot account, check the account before upload and use an explicit --account target.
The first upload may require an interactive project creation confirmation. Handle that deliberately rather than allowing repeated blind retries.
Use real combinations of line items, including discounts, missing classifications, long labels and regional variations.
Review the quote editor, preview, newly published quote and print/PDF output. They are related, but they are not identical rendering contexts.
ChatGPT is most useful as the client-context and prompt-strategy partner. Codex is most useful as the repository-aware builder. The workflow becomes stronger when each has a clear responsibility.
Custom-coded quote modules are not just a developer feature. They are a way to make Revenue Hub reflect how a business actually sells without abandoning HubSpot's native quote and line item model.
AI coding tools have lowered the barrier to building them, but they have not removed the need for consulting judgement. The quality of the outcome still depends on a clear brief, governed data, a tightly scoped build, safe deployment and testing against real buyer-facing output.
Used well, this workflow lets you keep HubSpot as the commercial source of truth while giving buyers a quote experience that matches the way the business sells.
Technical note: HubSpot's custom quote module and developer tooling documentation is evolving. Check the current prerequisites, starter project and CLI guidance before beginning a client build.