Skip to main content
Logistics · Odoo · Decision guide

Best carrier for Odoo ecommerce: SEUR, MRW, Correos Express, DHL, GLS, UPS and CTT, which to pick and which integration path

There is no best carrier for Odoo: there is the trio of carrier, volume and integration path. A comparison table read from the code of the OCA modules and our connectors, and a decision criterion with no fluff.

Odoo picking with the carrier label attached and the tracking number written on the picking

There is no best carrier for Odoo: there is a trio, carrier × volume × integration path, and the third is where most mistakes happen. With one service, few parcels per order and no cash on delivery, a well-implemented OCA module is enough. If you live off scheduled pickups or pickup points, you need a custom module that covers those calls. And with several carriers per country, or if other systems need the label, the integration goes to a shipping middleware and Odoo only sends the order.

Everything comes from reading code on 12 September 2026: in OCA/l10n-spain, delivery_seur_atlas, delivery_mrw and delivery_dhl_parcel (19.0) and delivery_gls_asm (18.0); in OCA/delivery-carrier, delivery_correos_express (19.0), delivery_ups_oca and delivery_cttexpress (18.0); and our Correos Express and MRW connectors.

What each carrier covers in Odoo, read from the code

Unless it says “custom”, the cell describes the OCA module; “No” means none of them does it. The branch is the one that exists on GitHub today, not the one a listing promises.

CarrierLabelPickupTrackingManifestPickup pointCustomsReturn
SEUR
OCA 19.0
PDF, ZPL, A4NoDaily cronNoNoNoNo
MRW
OCA 19.0 + custom
OCA PDF · custom ZPLCustom: date in the requestOCA daily · custom queryOCA: wizardOCA: delivery at franchiseNoOCA: return field
Correos Express
OCA 19.0 + custom
OCA PDF, ZPL · custom EPLCustom: create, change, cancelOCA daily · custom 30 minNoCustom: postcode and radiusNoNo
DHL Parcel
OCA 19.0
PDF, ZPL, EPLNoDaily cronDay-end closing (wizard)NoEmpty fieldsR2C product
GLS
OCA up to 18.0
PDF onlyCreate, cancel, statusesDaily cron + proof of deliveryWizardNoNo“With return” flag
UPS
OCA up to 18.0
PDF, GIF, ZPL, EPL, SPLNoDaily cronNoNoNoNo
CTT Express
OCA up to 18.0
PDF, PNG, BMPWizardDaily cronWizardNoNoNo

Of these seven, in Odoo 19 only SEUR, MRW, Correos Express and DHL Parcel have an OCA module. GLS, UPS and CTT stay at 18.0: migrating to 19 with one of them means migrating the module, which is OCA implementation work, or changing path.

Three things the table doesn't say. None of the seven OCA modules quotes rates except UPS: the SEUR one raises a NotImplementedError and the other five return the sales price of the shipping product, so the shipping cost is defined in Odoo. Tracking is updated in all of them by the same cron, the delivery_state one, with a one-day interval. And none of them, OCA or custom, sends a tariff code or declared value.

MRW or SEUR in Odoo: where they really differ for domestic B2C

On the label they do the same: you validate the picking, the shipment is created, the label is attached and the tracking is written on the picking. They differ in three functions that don't show up in a demo. Scheduled pickup: it doesn't exist in SEUR's OCA module. Our MRW connector sends the pickup date inside the request, calculated from the picking's scheduled date, moved to the next day after 17:00 and skipping weekends. MRW's OCA module sends the pickup node empty and rejects “pickup at franchise”, although it does support delivery at franchise.

Multi-parcel: SEUR's OCA module splits the weight equally among the parcels and sends dimensions of 1×1×1; it stores a single shipment number. Our MRW connector builds one line per parcel with its own weight and validates the data before calling. Cash on delivery: SEUR doesn't send it in any field; MRW's OCA module does, with the fee charged at origin or at destination and the amount taken from the order total. Selling cash on delivery is development on SEUR and configuration on MRW. Details in connecting SEUR to Odoo and in MRW Odoo connector.

GLS or DHL in Odoo: European parcel network versus international shipping

The criterion is not the label, it's the border. GLS Spain is a parcel network: small parcels, branches, volume. DHL in Odoo is two products with two APIs: the OCA module covers DHL Parcel only and its own description warns that it doesn't work for DHL Express, which is exactly the one Odoo 19 documents as a native connector, along with UPS. First check which DHL product you have contracted.

Customs: neither GLS nor DHL Parcel handle them. The DHL one includes the API fields, CustomsValue, CustomsCurrency and GoodsDescription, and all three travel empty; the incoterm only accepts CPT or EXW. The GLS one sends the declared value empty and the sender country fixed to 34, Spain. If you export outside the Union, Canary Islands, Ceuta and Melilla included, choose the path that lets you fill in that data. Details in DHL and GLS in Odoo.

GLS in Odoo: what the OCA module covers and when it's enough

delivery_gls_asm is the most complete of the three that don't reach Odoo 19. Read at 18.0.1.1.3: label in PDF only, with the format fixed in the EtiquetaEnvio call; pickups with their own creation, cancellation and statuses; proof of delivery attached to the picking; cancellation only if the shipment is still registered with the carrier; cash on delivery from the order total; a “with return” flag; and a manifest wizard. It's enough if you ship from Spain, on 17 or 18, with a printer that accepts PDF. Listing at GLS OCA.

UPS in Odoo: account, API keys and where the OCA module fails

delivery_ups_oca is the only one of the seven that really quotes rates: it calls /api/rating/v1/Rate and returns the price by weight and dimensions, with negotiated rates if you tick the checkbox. It asks for client id, client secret and shipper number, and renews the OAuth token by itself. Units default to inches and pounds (IN and LBS): if you don't change them, the rate comes out with the wrong weight. GIF label by default, converted to PDF if you choose; also ZPL, EPL and SPL.

Where it fails for international, which is what UPS is hired for: there is no reference to InternationalForms, commercial invoice or customs, so customs documentation is done outside Odoo. There are also no pickups, returns or pickup point; cash on delivery is supported. And there is no 19.0 branch. Listing at UPS OCA.

CTT Express in Odoo: what the integration requires and how tracking comes back

delivery_cttexpress is valid, according to its own description, for Spain and Portugal. It speaks SOAP with zeep against iberws.tourlineexpress.com, port 8686 in testing and 8700 in production, and asks for user, password and client, agency and contract codes. Label in PDF, PNG or BMP, with SINGLE or MULTI model; pickup with time slot and manifest, both through a wizard; tracking via GetTracking with the daily cron. It does no returns, cash on delivery, pickup point or customs, and has no 19.0 branch. Listing at CTT Express OCA.

Decision criterion by volume: when OCA, when a custom module, when middleware

We don't decide by company size but by where the repeated work is. Three questions, in this order.

  1. One carrier, one service, a usual single parcel and no cash on delivery? OCA module: it's free, the code can be read and label and tracking are there. Budget for the implementation: status mapping, lowering the cron interval and checking that the branch for your version exists.
  2. Do you live off a function that says “No” in the table? Scheduled pickup, pickup point, retries when the API goes down, prior credential validation. That is a custom module: our Correos Express one retries pending shipments every five minutes and syncs tracking every thirty; the MRW one blocks validation or only warns, depending on configuration.
  3. Several carriers per country, or does the shop also need the label? Shipping middleware: Odoo sends order and picking, the platform chooses the carrier and returns label and status. You pay per shipment and lose detail, but you can change carrier without touching Odoo.

The threshold: as long as nobody retypes addresses into the portal, integrating doesn't pay off; as soon as someone does, the OCA module pays off; when the warehouse prints labels through two paths, it's time for a custom module or middleware. More in native module versus OCA and in automating labels and tracking.

The three mistakes when choosing a carrier for Odoo

  • Choosing by shipping price and discovering the path later. Sales negotiates the rate; the warehouse suffers the path. A carrier without pickup in Odoo costs one person calling the branch every afternoon.
  • Believing the module listing instead of the branch. Request the manifest URL on the branch of your version and check whether it returns 200.
  • Testing with one parcel to Madrid. It's the only case that all of them handle well. Test three parcels of different weights, a cash on delivery and a shipment to the Canary Islands.
MRW shipping method form in Odoo with the Cash on Delivery, Integration Level and Delivery Product checkboxes
Shipping method form in Odoo: cash on delivery is a checkbox and the shipping cost comes from the delivery product, not from the carrier's API.

Frequently asked questions

Can UPS be connected to Odoo?

Yes. Odoo lists UPS among its native connectors in the version 19 documentation, and in OCA/delivery-carrier there is delivery_ups_oca for 17 and 18, with no 19 branch: it quotes in real time and creates labels, but doesn't generate customs documentation or pickups.

Does CTT have an Odoo module?

Yes, delivery_cttexpress in OCA/delivery-carrier, with branches 17.0 and 18.0: Spain and Portugal, label, pickup and manifest through a wizard, and tracking via cron. There is no 19.0 branch.

Which carrier has the best integration with Odoo?

On Odoo 19, Correos Express: between the OCA module and the custom connector they cover label, pickup, pickup point and tracking. The most complete one without buying anything is GLS, but it stays on Odoo 18. The only one that quotes rates is UPS.

OCA module or custom module for carriers in Odoo?

Label and tracking: OCA. Scheduled pickup, pickup point, retries and prior validation: custom. Several carriers per country or a label shared with other systems: middleware.

Useful links within FlexigoTech

Logistics in OdooThe seven carriers inside the pickingOCA module implementationInstall, adapt and maintain the community moduleSEUR Atlas OCAConnector listing and its credentialsDHL Parcel OCADay-end closing, cash on delivery and returnsCorreos Express connectorPickups, pickup point and trackingMRW connectorRetries, idempotency and prior validationServicesImplementation, integration and modulesSolutionsBy industry and by problem

What we do about this

Logistics integrationWhat it does, screenshots, versions and price.

Need to choose a carrier and don't know which path?

Tell us what you ship, how many parcels per order, to which countries and which Odoo version you have. We'll give you back the row of the table that applies to you and what is solved with configuration, what with a module and what with middleware. Write to comercial@flexigobe.com or call +34 616 809 504.

Talk to an engineer