Rich integration
Integration
With the SDK it's three lines: declare formats on inject(). Use the HTTP rich-delivery guide for ephemeral messages in groups.
bot.py
# Use in place of the ordinary handler; bot, dp and sk are initialized.from dataclasses import replacefrom aiogram import F, typesfrom sidekick_ads.router import sidekick_routerdp.include_router(sidekick_router(sk))@dp.message(F.text, F.chat.type == "private")async def handle_rich(message: types.Message):if message.from_user is None:returnreply = await get_llm_response(message.text) # Return plain text.result = await sk.inject(user_id=message.from_user.id,message=reply,language_code=message.from_user.language_code or "en",accept_formats=["text", "response", "card", "consent", "quiz"],capabilities={"rich_messages": True,"callbacks": True,"custom_emoji": False,},)if result.send:# A rich scene contains only the ad. Send the reply first.await message.answer(reply, parse_mode=None)ad = result.ad or {}# Keep the text fallback ad-only to avoid repeating the reply.ad_only = replace(result,message="Ad\n" + ad.get("text", ""),)delivered = await sk.send(bot, message.chat.id, ad_only)if delivered is None:# Record a delivery failure; do not request another ad.passelse:await message.answer(result.message, reply_markup=result.keyboard, parse_mode=None)
Client requirements
- •Rich blocks render on Telegram clients released 25.08.2026 or later. Older clients degrade softly: some blocks disappear, but the text and the classic
reply_markupCTA button (always duplicated by the server) stay visible. - •Custom-emoji brand logos render only when your bot owner has Telegram Premium — declare
capabilities.custom_emojiaccordingly. Without it the logo degrades to a bold brand name. - •Groups: interactive scenes after a tap are always delivered ephemerally (visible only to the tapping user). Scene 1 itself is ephemeral only when your bot is a chat admin (
bot_is_admin: true); otherwise it's a regular message — Telegram allows unprompted ephemeral sends to admin bots only.