ad2video
A service that turns the photos, description and equipment of a car listing into an ad video, built in partnership with OLX.
- Employer
- Groupe La Centrale
- Role
- Contributor at the start, then lead
- Period
- Stack
- TypeScript strict
- Node 24
- AWS Lambda
- SNS
- SQS
- DynamoDB
- DynamoDB Streams
- API Gateway
- CloudFront
- WAF
- KMS
- CDK v2
Context and problem
Car dealers publish their listings on La Centrale with photos, a description and a list of equipment. Together with OLX, we turn those listings into ad videos, generated by OLX's video API.
The service tracks the contracts and listings of 8,000 dealers. It has to generate each video at the right time, and never go over OLX's cap of 5,000 generations a day.
My role
I joined the project as a contributor at the start, then became its lead, in a team of 3 developers. A colleague built the base: syncing contracts and listings, and the read API. I designed and shipped the whole generation pipeline: listing eligibility, calls to the video API, status callbacks, then the daily batch and automatic video renewal. I also wrote the generation prompt with the team.
I am the direct technical contact for OLX's engineers, from design through delivery. Since the launch, I own the monitoring of the service and its improvements.
Architecture
The architecture is event-driven, on AWS:
- Dealer account events arrive through SNS into an SQS queue, processed in batches.
- A Lambda syncs contracts and listings into a single DynamoDB table, encrypted with KMS.
- DynamoDB Streams triggers the orchestration Lambda. It applies the throttling, fetches the photos from an internal service, builds the prompt and calls OLX's video API, with retries.
- The dealers' back office enables and views the videos through a private API Gateway, reachable only behind CloudFront and WAF.
The infrastructure is written in AWS CDK v2, with separate stateless and stateful stacks. The code is strict TypeScript on Node 24.
Key decisions
Defer a listing that was just generated
- Context
OLX enforces a cap of 5,000 generations a day. A listing can change several times a day, and each change can call for a new video.
- Choice
A first generation runs immediately. A listing already generated in the last 12 hours is deferred.
- Rejected alternative
The default option: generate a video on every listing change, deferring nothing.
- Consequence
The service stays under OLX's cap while producing 3,000 videos a day.
Move to a capped daily batch
- Context
Generating on every listing change made the number of calls to the video API hard to predict, and every generation is billed.
- Choice
Generation requests are stored in DynamoDB, in an index that only holds pending requests. A daily batch scheduled by EventBridge processes at most 3,000 requests per run, in arrival order. The batch time and size are CDK parameters.
- Rejected alternative
Keep generating right away and rely only on the last 12 hours delay to smooth the volume.
- Consequence
The daily volume is tuned without touching the code. Videos are also renewed automatically after 105 days, with at most 5 generations per listing.
Retry only the failed messages
- Context
Account events reach SQS in batches. One failing message must not hold back the others.
- Choice
Batch processing with partial failures, through
batchItemFailures: only the failed messages go back to the queue.- Rejected alternative
- The default option: a batch with one failure is retried in full.
- Consequence
A failed message is retried on its own, without processing the rest of the batch again.
A single way in: CloudFront and WAF
- Context
The API that enables and serves the videos is exposed to the dealers' back office.
- Choice
API Gateway's default endpoint is disabled: the API is reachable only behind CloudFront and WAF.
- Rejected alternative
The default option: keep API Gateway's public endpoint active next to CloudFront.
- Consequence
- No call can bypass the WAF rules.
Results
The service is in production. It produces 3,000 videos a day for 8,000 dealers, without going over OLX's cap of 5,000 generations a day.
AI in the product
I designed the generation prompt with the team. It is built from the listing's data: its description and its equipment. The video itself is generated by OLX's API.
Limits and what I would do differently
- The cap comes from outside. Throttling spreads generations over time, it does not add capacity: a listing edited several times waits for its new video.
- Generation depends on a partner API. Retries absorb a transient error, but the video then arrives later.