How Landen Dynamically Generates PDF Property Listing Brochures Using CMS Hub

Landen is a property listing and financial services company that deals with many properties across Australia. When selling a property, the company needs to create a property listing page, as well as a downloadable PDF brochure. They want to create these materials as quickly and easily as possible to manage multiple properties in the fast-paced real estate industry.

HubSpot’s CMS Hub enabled Landen to build a property listings website that is always up-to-date with their current inventory. Our serverless capabilities also gave Landen the ability to dynamically generate downloadable PDF brochures for each listing. The best part is it’s all powered by our modern content management system (CMS), making it easy for Landen’s team to produce the materials they need.

In this article, we’ll highlight how Landen leveraged HubSpot CRM and CMS tools to generate all their dynamic content. We’ll show you some code examples and discuss the practical steps for you to create these features for your own organization. You should be familiar with JavaScript, JSON, and Node.js to follow the demonstration.

How Landen Created Their Dynamic Property Listings Website

When Landen considered HubSpot’s tools, they initially thought HubDB might be a good fit for creating a website with dynamic property listings. They knew their team would find HubDB’s spreadsheet-like interface familiar and straightforward to use. But Landen also needed to generate custom reports based on sold properties and inactivate these listings on their website.

Landen discovered that if they used HubDB, they’d need to build a custom front-end tool to meet their reporting and display requirements. Building this tool would involve creating a login function, pulling data from HubDB, assembling reports, and then generating and presenting charts to the user. Building a custom tool like this would have been complex and time-consuming.

The property company wanted their solution to integrate with HubSpot’s charting and reporting tools. They realized that HubSpot’s custom objects integrate with reporting tools, providing Landen with the ability to run reports on all property sales.

The HubL templating language makes it straightforward for Landen to pull data from property listings stored as custom object records. The language enables Landen’s team to change each property listing’s status, automatically preventing properties from displaying on their website once they’re sold.

Custom objects provide the team at Landen with all the data they need while enabling them to use the same content to deliver a dynamic property listings website to potential clients. Let’s examine the code which makes a website like this possible.

Demo: Creating Custom Object Records

To get started creating custom object records, first create a free HubSpot CMS Developer Sandbox account. Then, install and connect the HubSpot CMS Command Line Interface (CLI) to your HubSpot account. Now you’re ready to start building.

Object schemas define CRM custom objects. A basic property listing object’s schema might look like this (property-listing-schema.json):

				
					{
  "name": "propertylisting",
  "labels": {
    "singular": "Property Listing",
    "plural": "Property Listings"
  },
  "requiredProperties": ["address", "status"],
  "searchableProperties": ["address"],
  "primaryDisplayProperty": "address",
  "properties": [
    {
      "name": "address",
      "label": "Address",
      "type": "string",
      "fieldType": "text"
    },
    {
      "name": "description",
      "label": "Description",
      "type": "string",
      "fieldType": "textarea"
    },
    {
      "name": "property_image",
      "label": "Property Image",
      "type": "string",
      "fieldType": "text"
    },
    {
      "name": "bedrooms",
      "label": "Bedrooms",
      "type": "number",
      "fieldType": "number"
    },
    {
      "name": "price",
      "label": "Price",
      "type": "number",
      "fieldType": "number"
    },
    {
      "name": "status",
      "label": "Status",
      "type": "enumeration",
      "fieldType": "radio",
      "options": [
        {
          "label": "For Sale",
          "value": "forsale"
        },
        {
          "label": "Sold",
          "value": "sold"
        }
      ]
    }
  ]
}
				
			

You can then use the CMS CLI to upload your custom object schema to your HubSpot account:

				
					hs custom-object schema create property-listing-schema.json
				
			

The CLI will confirm that you have successfully created the custom object. You can now start adding Property Listings records to your HubSpot account.

When you click on the Create Property Listing button, the application displays a form to enter all the details for a new property listing record.

You can upload a property image file to Marketing > Files and Templates > Files, then copy the URL and paste it in the Property Image field.

Demo: Creating a Property Listings Website

Now that you’ve created your property listing records, you need to display them to potential clients. Create a module that uses the HubSpot Markup Language (also known as HubL). HubL is an extension of the Jinjava templating engine and based on Jinja. The “all-properties” module template looks like this:

				
					{# modules/all-properties.module/module.html #}

{% set properties = crm_objects(
  "propertylisting",
  "status=forsale",
  "address, property_image, price"
) %}

<h1>Properties</h1>

{% for property in properties.results %}
<div class="property-listing">
  <img src="%7B%7B%20property.property_image%20%7D%7D" data-lazy-src="http://%20property.property_image%20?is-pending-load=1" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class=" jetpack-lazy-image" loading="lazy"><noscript><img data-lazy-fallback="1" src="%7B%7B%20property.property_image%20%7D%7D" loading="lazy"></noscript>
  <h2>{{ property.address }}</h2>
  <p>Price: ${{ property.price }}</p>
  <p><a href="/property?property=%7B%7Bproperty.id%7D%7D">View details</a></p>
</div>
{% endfor %}
				
			
This module uses the HubL crm_objects function to retrieve our property listing records. You’ll notice that the only property listings retrieved are listings where the status is forsale, as you don’t want to display unavailable properties. The property listings module includes links to view each property. Next is to create a “property-listing” module with a template to display the specific property listing’s full details:
				
					{# modules/property-listing.module/module.html #}

{% set property_id = request.query_dict.property %}

{% if property_id %}

  {% set property = crm_object(
	"propertylisting",
	property_id,
	"address, property_image, price, bedrooms, description"
  ) %}

  {% if property.address %}
	<h1>{{property.address}}</h1>

	<img src="%7B%7B%20property.property_image%20%7D%7D" data-lazy-src="http://%20property.property_image%20?is-pending-load=1" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class=" jetpack-lazy-image" loading="lazy"><noscript><img data-lazy-fallback="1" src="%7B%7B%20property.property_image%20%7D%7D" loading="lazy"></noscript>

	
  • Price: ${{property.price}}
  • Bedrooms: {{property.bedrooms}}

{{property.description}}

{% else %}

Sorry, this property could not be found.

{% endif %} {% else %}

No property listing was specified.

{% endif %}
This module gets the property ID from the URL query string. Next, it passes the ID into the HubL crm_object function to retrieve the matching property listing record. You need to create or use a CMS Theme to use these modules on your HubSpot website. You can learn how to do this in the Getting started with themes tutorial.

How Landen Generated Property Brochure PDFs

Landen used HubSpot’s serverless functions to generate a downloadable PDF brochure dynamically for each property listing. The serverless function calls the CRM API to retrieve a property listing’s custom object record. The function then sends this data to an AWS Lambda function, which uses Pug templates to generate an HTML page with the data. The Puppeteer library then renders the HTML page to PDF. The Lambda function sends the PDF back to the HubSpot serverless function, adding the correct response headers for a web browser to download the PDF. HubSpot’s serverless functions are flexible, so you can also generate PDFs with a more straightforward approach. Take a look.

Demo: Generating Brochure PDFs

You can use the HubSpot CLI to help you create a new serverless function:
				
					hs create function property-website
				
			

The CLI will then ask you a few questions:

				
					? Name of the folder where your function will be created
   generate-pdf-brochure

? Name of the JavaScript file for your function
   generate-pdf-brochure.js

? Select the HTTP method for the endpoint
   GET

? Path portion of the URL created for the function
   brochure
				
			
These actions will automatically create a generate-pdf-brochure.functions directory containing:
  • A configuration file (serverless.json)
  • A serverless function script (generate-pdf-brochure.js)
You can then run the CLI watch command to automatically upload changes to your HubSpot account:
				
					const hubspot = require("@hubspot/api-client");

const API_KEY = process.env.API_KEY;

exports.main = (context, sendResponse) =&gt; {
  (async () =&gt; {
    const hubspotClient = new hubspot.Client({ apiKey: API_KEY });

    const objectType = "propertylisting";
    const objectId = context.params.property;
    const properties = ["address,description,property_image,price,status"];

    try {
      const apiResponse = await hubspotClient.crm.objects.basicApi.getById(
        objectType,
        objectId,
        properties
      );

      const propertyListing = apiResponse.body.properties;

      // ... PDF generation code here ...

      sendResponse({
        statusCode: 200,
        headers: {
          "Content-Type": "application/pdf",
          "Content-Disposition": 'inline; filename="brochure.pdf"',
        },
        body: "<pdf_buffer_object>",
      });
    } catch (error) {
      sendResponse({
        statusCode: 500,
        body: {
          message: "Error generating property listing PDF",
        },
      });
    }
  })();
};</pdf_buffer_object>
				
			

The code above uses the Node.js HubSpot API Client to retrieve a property listing record by its object ID. The URL query string passes in the object ID, for example:

				
					https://<your-account-domain>.com/_hcms/api/brochure?property=12345678</your-account-domain>
				
			

You can use the property listing record’s data to populate a brochure PDF. You can also use a popular PDF generation library, such as PDFKit, to generate the brochure PDF. When you’ve created the PDF, you then send a response with the headers. Web browsers require these headers to download the PDF correctly.

You can learn more about serverless functions in HubSpot’s Getting started with serverless functions tutorial. Our Serverless Reference shows how you can add and configure your serverless functions to use secrets such as API keys.

Conclusion

Landen needed an efficient solution for generating dynamic property listings and brochure PDFs. By combining CRM custom objects, HubL markup language, and serverless functions, they delivered great content to their prospective buyers without burdening their team with desktop publishing tasks. Now buyers can find the properties they desire, the sales team has the materials they need to close the deal, and investors earn the best possible return on investment.

Similar methods can help your organization create retail listing or pet adoption websites, produce event posters or flyers, and so much more. CMS Hub helps you quickly build applications without running your own server. Now that you’re inspired by Landen’s success, it’s the perfect time to try CMS Hub.

If you’re interested in developing expert technical content that performs, let’s have a conversation today.

Facebook
Twitter
LinkedIn
Reddit
Email

POST INFORMATION

If you work in a tech space and aren’t sure if we cover you, hit the button below to get in touch with us. Tell us a little about your content goals or your project, and we’ll reach back within 2 business days. 

Share via
Copy link