Rightmove dominates UK property search with over 130 million visits monthly. For letting agencies, advertising properties on Rightmove isn't optional—it's essential. But Rightmove's Real Time Datafeed (RTDF) API is notoriously complex: it requires P12 certificate authentication, expects deeply nested XML-style JSON payloads, enforces strict data validation, and has particular requirements about photo URLs and property addresses.
Week 37 implemented complete Rightmove integration as the first real-world test of our new apps system. This article explores the technical challenges we encountered and how we solved them whilst maintaining the flexibility our apps architecture provides.
What Your Team Will Notice
Once configured, Rightmove integration operates invisibly. Create a property, add photos, set the rent price—and within minutes that property appears on Rightmove exactly as entered in LetAdmin. Update the description or change the rent, and Rightmove reflects those changes automatically through webhook-triggered synchronisation.
The integration respects your advertising workflow. Properties marked "Not For Advertising" never send to Rightmove. Those marked "Available" or "Under Offer" sync with appropriate status indicators. When a property lets, marking it "Let" automatically removes it from Rightmove, keeping your portal listings aligned with actual availability.
Photo management becomes seamless. Drag photos to reorder them in LetAdmin, and that ordering flows to Rightmove. Add a new photo, and Rightmove receives it within seconds. Delete a photo, and it disappears from the portal automatically. The integration maintains photo ordering consistency across platforms, ensuring your best property images always display prominently.
For agencies managing multiple branches, the integration handles branch-specific configuration. Each branch maintains its own Rightmove credentials and branch identifiers, with properties routing to appropriate Rightmove branches automatically based on agency structure.
Under the Bonnet: Enterprise API Authentication
Rightmove's API uses P12 certificate authentication rather than API keys. This provides stronger security but requires careful implementation:
# High-level authentication approach
# Actual implementation includes additional security measures
class RightmoveApiService
def initialize(property)
@property = property
@installation = fetch_rightmove_installation
@certificate = parse_p12_certificate(@installation.settings['certificate'])
end
def send_property
# Constructs HTTP client with certificate authentication
# Makes API request with proper headers and certificate verification
# Handles certificate expiry and renewal workflows
end
end
The certificate lives in the app installation's encrypted settings, accessed only when making API calls. Certificate parsing happens securely without exposing the certificate data to logs or error tracking.
Complex Property Serialisation
Rightmove expects properties in a specific nested structure that differs significantly from LetAdmin's database schema. A serialiser class handles this transformation:
class RightmovePropertySerializer
def initialize(property, branch_id)
@property = property
@branch_id = branch_id
end
def to_rightmove_payload
{
network: {
network_id: @branch_id
},
branch: {
branch_id: @branch_id,
channel: 1, # Lettings channel
overseas: false
},
property: build_property_data,
details: build_property_details,
media: build_media_section,
price_information: build_pricing
}
end
end
This serialiser consolidates all Rightmove-specific mapping logic in one place, making it easy to update when Rightmove's API evolves. The serialiser handles numerous edge cases:
Address Privacy
Rightmove requires a display_address that shows general location without revealing the exact property:
def build_display_address
# Removes house numbers and property identifiers for security
# Shows only: street name, town, postcode area
# Example: "High Street, Worcester, WR1" (not "123 High Street")
parts = [
sanitised_street_name, # Removes leading numbers
@property.town,
@property.postcode_area # First part only: "WR1" not "WR1 2AB"
].compact
parts.join(', ')
end
This privacy protection prevents prospective tenants identifying properties before viewing arrangements are made, a security requirement for occupied properties.
Property Type Mapping
LetAdmin's property types don't map directly to Rightmove's taxonomy. The serialiser handles translation:
def map_property_type
mapping = {
'flat' => { type: 0, style: 'Apartment' },
'house' => { type: 1, style: 'Terraced' },
'bungalow' => { type: 2, style: 'Detached' },
'studio' => { type: 0, style: 'Studio' }
}
mapped = mapping[@property.property_type] || { type: 1, style: 'House' }
{
property_type: mapped[:type],
property_sub_type: mapped[:style]
}
end
This ensures property types display correctly on Rightmove regardless of how agencies categorise them internally.
Outside Space and Parking
Rightmove has specific enumerations for outside space types and parking arrangements:
def build_outside_space
return [] unless @property.outside_space_type.present?
spaces = []
spaces << 'Private Garden' if @property.outside_space_type == 'private_garden'
spaces << 'Communal Gardens' if @property.outside_space_type == 'communal_garden'
spaces << 'Balcony' if @property.outside_space_type == 'balcony'
spaces << 'Terrace' if @property.outside_space_type == 'terrace'
spaces
end
def build_parking
return [] unless @property.parking_type.present?
parking = []
parking << 'Allocated Parking' if @property.parking_type == 'allocated'
parking << 'Garage' if @property.parking_type == 'garage'
parking << 'Off Street Parking' if @property.parking_type == 'off_street'
parking
end
These attributes enhance property listings with features tenants frequently search for.
Council Tax Banding
Rightmove requires council tax bands for most properties:
def build_council_tax
return nil if @property.council_tax_band.blank?
return nil if @property.council_tax_band == 'TBC' # Don't send "To Be Confirmed"
@property.council_tax_band # 'A' through 'I'
end
This conditional logic ensures only confirmed council tax bands appear on listings, avoiding confusion from placeholder values.
Photo Migration Challenge
Rightmove requires photos to have file extensions in their URLs (.jpg, .png, etc.). Our existing S3 storage used content-addressable filenames without extensions, causing Rightmove to reject photo URLs. We needed to migrate 2,600+ photos whilst maintaining existing functionality.
The solution involved a rake task that:
- Iterates through all photos in the database
- Detects current file extension from S3 metadata
- Copies each photo to a new key with proper extension
- Updates database records with new keys
- Verifies new URLs are accessible before committing changes
# lib/tasks/migrate_photo_extensions.rake (simplified)
task migrate_photo_extensions: :environment do
PropertyPhoto.find_each do |photo|
next if photo.filename.include?('.') # Already has extension
# Detect extension from content type
extension = extension_from_content_type(photo.content_type)
new_filename = "#{photo.filename}#{extension}"
# Copy to new key with extension in cloud storage
copy_with_extension(photo, new_filename)
# Update database record
photo.update!(filename: new_filename)
end
end
This migration ran successfully across all environments, with rollback capability if issues arose.
Direct S3 URLs and Length Limits
Rightmove imposes URL length limits. Initially, we used Rails-generated URLs that included lengthy query parameters for authentication. These exceeded Rightmove's limits for properties with many photos.
The solution: pre-signed direct S3 URLs with longer expiry times:
def generate_photo_url(photo)
# Generates direct S3 URL with extended expiry
# Bypasses Rails URL helpers to keep URLs short
# Includes necessary authentication without lengthy parameters
photo.blob.service_url(expires_in: 7.days, disposition: 'inline')
end
This reduced average photo URL length by 60%, comfortably fitting within Rightmove's requirements even for properties with dozens of photos.
API Operations
The Rightmove integration supports three primary operations:
Send Property: Creates or updates a property listing on Rightmove with complete data including photos, pricing, and availability status.
Remove Property: Deletes a property from Rightmove when it lets or becomes unavailable, using the property's unique reference for identification.
Get Branch Property List: Retrieves all properties currently advertised under a branch, enabling synchronisation checks and reconciliation.
These operations integrate with the webhook system—property updates trigger webhooks that queue Rightmove sync jobs, keeping portal listings current with minimal latency.
Testing Strategy
Testing external API integrations requires careful mocking to avoid hitting production APIs during tests. We created a comprehensive test helper:
class RightmoveTestHelper
def self.test_send_property(property_reference)
# Provides console testing capability
# Sends to Rightmove staging environment
# Reports success/failure with detailed error messages
end
def self.verify_payload_structure(property)
# Validates payload structure without making API call
# Checks all required fields are present
# Verifies data types match Rightmove expectations
end
end
This allowed manual verification against Rightmove's staging environment before deploying to production, catching payload structure issues early.
Automated tests mock HTTP responses:
RSpec.describe RightmoveApiService do
it "sends properties with correct payload structure" do
# Mocks successful Rightmove response
# Verifies payload serialisation is correct
end
it "handles certificate authentication errors gracefully" do
# Mocks certificate rejection
# Confirms error handling notifies appropriately
end
it "removes properties when marked as let" do
# Verifies RemoveProperty API call triggers correctly
end
end
This test suite provides confidence that the integration handles both happy paths and error scenarios correctly.
What's Next
The Rightmove integration validated our apps architecture—it handled complex authentication, intricate payload requirements, and significant data migration challenges. This success paves the way for additional property portal integrations (Zoopla, OnTheMarket) that follow similar patterns but with different payload structures.
Future enhancements include two-way synchronisation (importing enquiries and viewing requests from Rightmove back into LetAdmin), performance portal analytics (tracking which properties receive most views and enquiries), and automated compliance checking (ensuring all required fields are complete before attempting Rightmove sync).
The integration transforms how agencies manage their Rightmove presence: instead of maintaining property data in two systems with manual synchronisation, they manage everything in LetAdmin with automatic portal updates, reducing administrative burden whilst improving listing accuracy.