# Luxembourg ALVA Latest Food and Feed Alerts (`thatmike1/lu-alva-food-alert-notices`) Actor

Export only the latest Luxembourg ALVA homepage food and animal-feed alerts, with French titles, summary text, publication dates and original category tokens.

- **URL**: https://apify.com/thatmike1/lu-alva-food-alert-notices.md
- **Developed by:** [Michal Pšenčík](https://apify.com/thatmike1) (community)
- **Categories:** Business, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 72.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.00005 / actor start

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Luxembourg ALVA Latest Food and Feed Alerts

Export the alerts the [Luxembourg food safety portal](https://securite-alimentaire.public.lu/fr.html) currently promotes in the "Alertes alimentaires" section of its homepage, as one dated, hashed JSON bundle: every alert's notice URL, publication date, French title, summary text and the source's own category tokens. Human-food recalls and animal-feed recalls are both kept, side by side.

It suits a Luxembourg food or pet-food retailer or importer that polls the national homepage once a day and adds the promoted alerts to an internal review queue. The bundle is a snapshot of what the ALVA (Administration luxembourgeoise vétérinaire et alimentaire) homepage shows. It is not a list of every Luxembourg recall, not a stock match and not proof that any product is safe.

This Actor is independent of the ALVA and the Luxembourg government.

### Input

```json
{ "requestIntervalMs": 1500 }
```

- `requestIntervalMs` (integer, 1300 to 10000, default 1500): idle time after every response before the next request. A run fetches one fixed homepage, so the interval only matters when a retry or redirect happens.

Empty input uses the default. Unknown fields and non-integers are rejected before any request. There is nothing to filter: every run reads the same page.

### Output

Each successful run stores exactly **one dataset item**: the complete bundle for the alert section. A run that fails before delivery (invalid input, a source error, a layout change) stores nothing. The one exception is `delivery_uncertain`, described under Coverage and limits.

```json
{
    "schemaVersion": "1",
    "sourceId": "lu-alva-home-alerts",
    "sourceUrl": "https://securite-alimentaire.public.lu/fr.html",
    "observedAt": "2026-10-24T13:05:03.275Z",
    "coverage": "homepage_alert_section_only",
    "items": [
        {
            "noticeUrl": "https://securite-alimentaire.public.lu/fr/actualites/rappels-aliments-pour-animaux/2026/10/rappel-filet-bites-thon-anchois-de-la-marque-moments.html",
            "publishedDate": "2026-10-20",
            "publishedDateRaw": "20.10.2026",
            "title": "Rappel : Filet Bites thon & anchois de la marque MOMENTS",
            "summary": "Présence possible de fragments d'arêtes de poisson",
            "categoryTokens": ["rappels-aliments-pour-animaux"]
        }
    ],
    "snapshotHash": "7b6d1cc1094b7df152a857606d7edf48714516b8fe5c8bffabc1d9a7c580f490"
}
```

The example shows one of the three alerts the homepage promoted on 24 October 2026 (a dried-savory food recall, this pet-food recall and a cooked-shrimp food recall).

- `observedAt` is the UTC instant the homepage response completed.
- `items` holds 1 to 20 alerts, sorted by `publishedDate` descending, then `noticeUrl`. `noticeUrl` is the stable identity of an alert; it points to either a food alert (`/fr/actualites/alertes/`) or an animal-feed recall (`/fr/actualites/rappels-aliments-pour-animaux/`). `publishedDate` is the page's `datetime` value (`YYYY-MM-DD`, no time or timezone) and `publishedDateRaw` the `DD.MM.YYYY` label it shows; the run checks they agree. Titles and summaries stay in French with whitespace collapsed. A summary can be an empty string.
- `categoryTokens` are the alert's own CSS class labels on the homepage, such as `rappels-de-produits` or `rappels-aliments-pour-animaux`, sorted. They are source labels, not a translated taxonomy, and new labels are passed through.
- `snapshotHash` is the SHA-256 of the canonical JSON of the bundle without `snapshotHash`, `observedAt` and `sourceUrl`. Two runs with the same content have the same hash, so you can skip unchanged snapshots on your side. Content returning to an earlier state returns to its earlier hash, so the hash is not an event ID.

A free `SUMMARY` record in the default key-value store explains every run: status, stop reason, errors, request and byte counts, HTTP statuses, parsed and deduplicated alert counts, stored and charged bundle counts, and what the run did not cover.

### Pricing

Pay per event, two built-in events:

| Event                      | Price    | When                                                    |
| -------------------------- | -------- | ------------------------------------------------------- |
| Actor start                | $0.00005 | Once per start unit when a run starts                   |
| Food and feed alert bundle | $0.001   | Once per complete bundle actually stored in the dataset |

A successful default run at 256 MB costs **$0.00105** in Actor event fees; 30 daily runs cost **$0.0315**. Every successful run is billed for its bundle, including runs whose content is unchanged. A run that fails before delivery stores no bundle and is not charged for one; the start fee still applies. A `delivery_uncertain` run may already have stored, and been charged for, its bundle. If your spending limit cannot cover one bundle, the run does not fetch the source and stops with `spending_limit`.

### Coverage and limits

- **Homepage alert section only.** The homepage promotes a few recent alerts (three on 24 October 2026) and the ALVA chooses them editorially. An alert leaving the homepage is never a withdrawal, a resolution or the end of a recall. The alert archive, its search, notice pages, PDFs, lot numbers and full article text are never fetched.
- The neighbouring "Actualités" news section uses the same layout and is left out on purpose.
- No severity, status, affected batches or market coverage is inferred from a title or category.
- Stateless: no baseline, no change events, no exactly-once promise. Each run delivers the whole current section; compare hashes or notice URLs yourself.
- One request to one fixed URL per run. At most 5 HTTP requests including retries and redirects, 2 MiB per response, 6 MiB per run and 90 seconds of source work. Timeouts, connection resets and 5xx responses are retried at most twice, after 2 and 4 seconds plus the request interval. Redirects are followed only back to the same homepage URL, at most 3.
- A 403, a 429 or a challenge or block page (also inside a 200 response) stops the run with `source_blocked` or `source_throttled`. No proxy, browser, cookies or workaround is used.
- A page whose layout no longer matches (no single "Alertes alimentaires" section, a missing link, title, summary or date, a date label that disagrees with its `datetime`, a link to anywhere other than an alert notice, more than 20 alerts, no alerts, or a page cut off before its end) fails with `source_layout_changed` and stores nothing. It never becomes an empty or shortened bundle.
- If the push was sent but the dataset cannot confirm the bundle (for example, the readback fails), the run fails with `delivery_uncertain` instead of claiming delivery. The bundle may still have been stored and charged: check the run's dataset before you retry, because a retry stores and charges a new bundle.

Retry a failed run with the same input; there is no partial state to resume.

### Source and data

Source: the ALVA's public food safety portal, securite-alimentaire.public.lu. The bundle keeps public factual alert text only and omits contact details. If a source string names a person, you are the controller for how you use it.

For support, open an issue on this Actor's Issues tab with the run ID and the `stopReason` from `SUMMARY`.

# Actor input Schema

## `requestIntervalMs` (type: `integer`):

Idle time after every securite-alimentaire.public.lu response before the next request, retries and redirects included. The run fetches one fixed homepage, so this only matters when a retry or redirect happens.

## Actor input object example

```json
{
  "requestIntervalMs": 1500
}
```

# Actor output Schema

## `bundle` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("thatmike1/lu-alva-food-alert-notices").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("thatmike1/lu-alva-food-alert-notices").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call thatmike1/lu-alva-food-alert-notices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thatmike1/lu-alva-food-alert-notices"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/llNmQQ4Z4N0IXLJtQ/builds/XW0o6yszffXDEwAHQ/openapi.json
