Odoo Community Association

Social Media Advertising

Beta License: AGPL-3 OCA/social Translate me on Weblate Try me on Runboat

This module adds the advertising layer on top of Social Media Base: the campaigns used to promote the posts, the groups that manage several campaigns as a unit, the tags that classify them and the view of the ads served by the social media.

Everything is generic, so it works with any social media. Each connector module plugs its own social media through the extension hooks, and contributes its own submenu under Advertising: campaign groups, campaigns and ads belong to a single social media, so they are never listed mixed together.

Main features:

Table of contents

Configuration

Security groups.

  • The module reuses the groups of Social Media Base.
  • Social Media / User: Own Accounts sees only the campaigns he is responsible for, and can create campaign groups and tags but not delete them.
  • Social Media / Administrator sees every campaign and is the only group that manages the stages.

Advertising environment.

  • Go to Social Media > Configuration > Accounts, open an account and its Advertising tab.
  • Environment, in the Advertising tab, tells the advertising API of the social media which entities it must answer for this account.
    • Test only sees the test advertising accounts of the application, their campaigns and their ads. Nothing is ever served to a real audience and nothing is ever billed, which is why it is the default.
    • Production sees the real advertising accounts. A campaign created from Odoo in this environment spends a real budget once it is activated in the campaign manager of the social media.
  • The environment does not affect the publication of posts. A post published from an account set to Test is a real post on the social media, visible to everybody. The setting only governs the advertising features.
  • The two environments never share an advertising account, so changing the environment drops the advertising account in use.
  • The tab only shows up when an advertising connector module is installed for the social media of the account.

Stages.

  • Go to Social Media > Configuration > Stages > <social media>, a menu every connector module contributes for its own social media.
  • A stage mirrors a status the social media gives to a campaign, a campaign group or an ad. It belongs to one social media and one scope, set in the Applies To field.
  • Code is the value the social media returns, for example ACTIVE or PENDING_DELETION. It is what the connector module matches when it imports, so it must be written exactly as the social media sends it.
  • Level is the colour of the badge showing the stage.
  • This module ships no stage: each connector module declares the stages of its own social media in its data/ folder. Until a connector is installed, the Stage field has no option to choose from.

Connector modules.

  • To resolve a remote status, call self.env["social.stage"]._get_stage(media_type, applies_to, code). It returns the stage, or an empty recordset when the connector has not declared that code.
  • To make a social media selectable on the campaigns, extend social.advertising.campaign._available_campaign() and append your own media type.
  • To restrict the social media campaigns that can be linked to a post, extend social.post._get_allow_social_campaign_domain().
  • To freeze another field of the post once it is published, extend social.post._get_locked_content_fields(), as this module does with the social media campaign.
  • To list the advertising accounts of a social media, extend social.account._advertising_media_types() with your own media type, which is what makes the Advertising tab show up, and implement social.account._fetch_advertising_accounts() returning one dict of values per advertising account, with remote_ref, name and environment. The generic module takes care of creating, updating and dropping the social.advertising.account records, and of keeping the one in use.
  • To add what only your social media reports, inherit social.advertising.account and declare your own fields, as Social Media Advertising Linkedin does with the serving status.
  • To show your records, contribute a menu named after your social media under social_media_advertising.social_advertising_menu, with one ir.actions.act_window per model filtered on [("media_id.media_type", "=", "<your media type>")], and another one under social_media_advertising.social_stage_root_menu for your stages. Both menus of this module are only containers: they hold nothing until a connector fills them, and Odoo hides them meanwhile.
  • To import the campaigns and the campaign groups of a social media, implement social.account.action_import_campaigns() and return success, message and the number of imported groups, campaigns and ads. It is what the Fetch campaigns button of the account calls.
  • To list the ads, implement social.account._fetch_ads(), returning one dict of values per ad, each carrying its remote_ref, and social.account._fetch_ad_refs(), returning only the references: the first is what Sync ads mirrors, the second is the cheap call the six-hour cron checks with.
  • To delete an ad on the social media, implement social.advertising.ad._delete_remote_ad() and answer _compute_can_delete_remote_ad() for the ads your API accepts a deletion on. Extend _register_remote_ad_gone() to leave on the archived ad the status your social media gives a deleted one, and _advertising_ad_action() to send the user back to the list of your own social media.
  • To give a record its address on the social media, implement _get_web_url() on social.advertising.account, social.advertising.campaign, social.advertising.campaign.group or social.advertising.ad: the Open … button of the form shows up as soon as it answers one.

Usage

Choose the advertising account.

  • Go to Social Media > Configuration > Accounts, open an account and its Advertising tab.
  • Click Fetch advertising accounts. The advertising accounts the authorized member may reach are brought from the social media and listed read-only: they mirror the social media and are never pushed back.
  • Only the advertising accounts of the current environment can be used, so check the Environment first.
  • Click Use this account on the row you want the campaigns and the ads to belong to. It is highlighted and marked In Use, and any other one is unmarked: one advertising account at a time per social media account.
  • Nothing works until one is marked. When the environment leaves exactly one candidate, it is marked In Use automatically, both when the advertising accounts are fetched and when the environment changes. With several candidates none is chosen and you have to pick one: campaigns, campaign groups and ads all belong to a single advertising account on the social media, so guessing one would silently work against the wrong advertiser. A choice already made is never replaced. While none is in use, importing and creating campaigns is refused with a message saying so, and no ad is fetched.
  • Fetching again refreshes the list without changing your choice. An advertising account that no longer exists on the social media is dropped from the list, unless the social media returns no account at all: in that case nothing is removed, because an empty answer cannot be told apart from a temporary failure.
  • Go to Social Media > Advertising > <social media> > Advertising accounts for the list of the advertising accounts of that social media, with filters by environment and by the one in use. Open one to see its details, its Campaigns and Campaign Groups stat buttons, and the Open advertising account button, which opens it on the social media in a new tab.
  • A campaign and a campaign group record the advertising account they belong to when they are created on the social media or imported from it, and it never changes afterwards, except when the advertising account itself disappears from the social media on a Fetch advertising accounts: it is then dropped and the campaigns and the campaign groups are left without a link. Choosing another advertising account therefore does not move the campaigns already created: the stat buttons keep showing the history as it happened. A campaign or a campaign group holding no advertising account is linked on the next Fetch campaigns.

Stat buttons of the account.

  • Go to Social Media > Configuration > Accounts and open an account.
  • Campaigns and Campaign Groups cover every advertising account of the social media account, not only the one in use.
  • Ads opens the ads of that account with the standard search bar, so they can still be filtered by date, grouped and saved as a favourite.
  • All three are only shown for a social media whose connector module manages advertising. The Marketing Campaigns button next to them comes from Social Media Base and is always shown: a marketing campaign needs no advertising connector.

Generate a campaign group.

  • Go to Social Media > Advertising > <social media> > Campaign Groups > New
  • A form view opens; fill in the required fields CREATE_GROUP_CAMPAIGN
  • Save
  • The Campaigns stat button on the form shows the number of campaigns of the group and navigates to them.
  • The Open campaign group button opens the campaign group on the social media, in a new tab. It only shows up once the campaign group exists there.

Generate a campaign.

  • Go to Social Media > Advertising > <social media> > Campaigns > New
  • Fill in the fields. The social media is optional; when a social media is selected, the campaign group and the accounts become required. CREATE_CAMPAIGN
  • Save
  • Changes on the main campaign fields are logged in the chatter.
  • A campaign can target several accounts of the same social media. A connector module may restrict it: LinkedIn campaigns accept a single account, because the campaign belongs to one advertising account there.
  • The Open campaign button opens the campaign on the social media, in a new tab. It only shows up once the campaign exists there.

Campaign and campaign group stages.

  • The status bar of the campaign form and the Stage field of the campaign group show the status the social media gives to the record.
  • Only the stages of the social media selected on the campaign are offered, and only those whose Applies To matches the record.
  • The stages are declared by each connector module, see the configuration section.

Link the campaigns to a post.

A post carries two independent campaigns, and both are optional:

  • Campaign is the Odoo marketing campaign (utm.campaign), the same one used by the mailings, the leads and the UTM tracking. Any of them can be selected.
  • Social campaign is the campaign of the social media, the one holding the budget, the campaign group and the reference used to publish a sponsored post. Only social campaigns whose social media matches the accounts selected on the post can be chosen. A connector module narrows the list further with the rules of its social media, so what is offered are the campaigns that can actually sponsor this post: see the LinkedIn ad formats in Social Media Advertising LinkedIn.
  • Editing the content of the post can invalidate the social campaign already chosen. When that happens the field is cleared as soon as the content changes, instead of letting the post fail when it is published. Pick another campaign among the ones then offered.

Both are propagated to the publications of the post. A publication imported from the social media keeps whatever its connector was able to resolve.

Both are frozen, like the rest of the content of the post, as soon as one of its accounts publishes: they decide how the post goes out, so changing them afterwards would no longer describe what is online.

PUBLICATION_CAMPAIGNS

Ads.

  • Go to Social Media > Advertising > <social media> > Ads

  • The view is empty until the first synchronization. The Sync ads button brings the sponsored creatives of every account the user is responsible for, and it is the only thing that does: the view shows the picture of the last synchronization, not what the social media serves right now. Each ad carries the moment it was last fetched.

  • An ad is named after the text of the post it promotes, which is what it is recognized by. An ad promoting a post this database does not know is named Post not available.

  • Every ad shows its status, its campaign, the publication it promotes and its statistics. The cards carry no image, so they all keep the same shape whether the promoted post has one or not: the images are shown on the publication, which the Publication button opens. The Open ad button opens the ad itself on the social media, not the campaign it belongs to. The status is the one set by the advertiser on the social media, with the name and the colour of the matching stage; the reason why the social media is serving the ad or not is only shown on the form of the ad.

  • The statistics cover the window shown next to them. They are not the figures of the whole life of the ad.

  • The search bar is the standard one: filter by creation date, group by account, advertising account, campaign or status, and save a favourite. The panel on the side filters by status and by account.

  • Only the ads of the advertising account in use are fetched. The ones of the other advertising accounts stay as they were last synchronized and are marked Advertising account not in use; the Advertising account in use filter leaves them out.

  • Deleting an account permanently takes with it what only that account could reach: its advertising accounts, its ads, and the campaigns and campaign groups that exist on the social media. What was written here and never published is kept, and only loses the account that is going away; so is a campaign shared with an account that stays, and a group that still holds a campaign of somebody else.

  • An ad the social media stops answering is archived, never deleted: its statistics are the only trace left of what it did, and the connector leaves on it the status its social media gives a deleted ad. The Delete permanently button, reserved to the administrators and to the archived ads, is what removes that history from Odoo when it is not wanted; the confirmation says what is lost. Nothing is deleted on the social media, which no longer serves that ad anyway.

  • The Delete ad button deletes the ad on the social media, not only in Odoo, and it cannot be undone. It is only shown for the social media whose connector deletes an ad, and only the responsible user of the account and the social media administrators may press it. What the social media answers decides what is left in Odoo: an ad the social media deletes on the spot loses its record here as well, along with its statistics, while one that is only taken for deletion keeps its record with the status the social media reports until it is processed.

  • An ad the social media stops serving is archived, never deleted, so its statistics survive. Archiving an account archives its ads too; deleting it deletes them.

  • A cron checks every six hours whether the social media serves ads this database does not know yet. No ad is fetched: it only raises a flag on the account. The responsible user gets a notice on the ads view, and the New ads available badge stays there across reloads until the ads are synchronized, so the user decides when to press Sync ads.

    ADS

Fetch campaigns.

  • The account form provides a Fetch campaigns button when the connector module adds it. Each social media module implements the actual import; a notification shows the result.
  • The import can also link the publications already brought from the social media with the campaign they belong to, when the connector is able to resolve it.

Archiving.

  • Archiving an account also archives its campaigns and their campaign groups.
  • A campaign shared by several accounts is only archived when all of its accounts are, whether they are archived together or one by one, and a campaign group is only archived when it has no active campaign left.
  • Unarchiving the account restores its campaigns and their campaign groups. The ads are not brought back: an ad is also archived when the social media stops serving it, so unarchiving them all would resurrect the ones it dropped, and the next synchronization is what restores the ones still served.
  • Deleting an account permanently deletes, in Odoo, the campaigns and the campaign groups that exist on the social media; nothing is deleted on the social media itself. A campaign that was only written in Odoo and never reached the social media is kept, and it only loses the link to the account; a campaign group is kept as long as it still has a campaign.

Campaign ownership.

  • Every campaign has a Responsible user, set to whoever created it. A regular user of the Social Media / User: Own Accounts group only sees the campaigns he is responsible for; the Social Media / Administrator group sees all of them.

Notifications you may never see.

  • The check for new ads runs every six hours and raises a notice on the ads view when the social media serves an ad this database does not know about. It needs an advertising account marked as in use on the social media account: without one there is no advertiser to ask, the check reads nothing and the notice never goes up.

Known issues / Roadmap

Kanban view of the campaigns.

The fold field of social.stage is meant for a kanban of the campaigns grouped by stage, which is not implemented yet. Until then the field has no visible effect.

Tags without colour.

social.tag only has a name: it has neither a colour field for the many2many_tags widget nor a uniqueness constraint on the name, so two tags can share it.

Campaign groups and tags are shared data.

social.advertising.campaign.group and social.tag have no responsible and no record rule, so every social media user sees and edits all of them, unlike the advertising accounts, the campaigns and the ads, which are restricted to their responsible. Scoping them is left for a later version.

Campaign visibility of a shared post.

The record rule of social.advertising.campaign restricts a user to the campaigns he is responsible for. If an administrator assigns a post to a user and that post is linked to a campaign of somebody else, that user cannot open the campaign from the post, and the Social Campaign field offers him nothing to choose from. A finer rule, for instance sharing the campaigns of a campaign group, is left for a later version.

Statistics of a single window.

There is no history per day, so the evolution of an ad cannot be charted: a new synchronization replaces the statistics of the previous one. Charting it needs a table of facts per day, the way social_media_base already keeps one for the accounts in social.account.statistics, and giving the advertising models the same treatment is a feature of its own.

remote_ref is writable through RPC.

The views hide remote_ref, and on the ads and the advertising accounts the ACL backs it: a social media user only reads them. The campaigns and the campaign groups are the ones he writes, so on those two he can still change or empty the field through RPC and orphan the record on the social media. Restricting the field is a hardening candidate for a later version.

Connector modules without an advertising layer.

Only LinkedIn has its advertising connector, Social Media Advertising LinkedIn. The other connectors of the family, such as social_media_x, have no advertising module yet: their accounts publish posts but do not manage campaigns.

Records without a social media are out of every menu.

The lists of campaign groups, campaigns and ads are filtered on the social media they belong to. A campaign saved without one, or a campaign group whose campaigns mix social medias, which empties its media, is therefore reachable only through a stat button or a saved filter.

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed feedback.

Do not contact contributors directly about support or help with technical issues.

Credits

Authors

  • Binhex

Contributors

Other credits

This work has been funded by AEOdoo (Asociación Española de Odoo - https://www.aeodoo.org)

Maintainers

This module is maintained by the OCA.

Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

Current maintainer:

edescalona

This module is part of the OCA/social project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.