SEO of the site
Technical SEO for my own site, maksutovdesign.ru: 268 pages in four languages with no CMS. Which rules I introduced so that a search engine understands every page the same way, what it produced in numbers as of 3 October 2026, and how this differs from "we set up a plugin".
01 / task
No CMS means SEO has to be built with scripts and verified with numbers
In WordPress a plugin handles canonical and the sitemap. Here every page is a separate HTML file, so the same meta information would have to be kept by hand in 268 places. The goal was to turn SEO from a set of scattered fixes into a repeatable process: a shared rule, a generator, a check, and the result recorded in numbers.
02 / technical pack
Canonical, hreflang, Open Graph and JSON-LD — on every page
On 6 September 2026 I applied a single technical pack to the site, following the recommendations of the book "The Craft Bible" (appendices A and B — launch readiness and Schema.org markup). The block is inserted into <head> between seo-pack markers and built by one idempotent script: it can be run repeatedly, never duplicates data, and rebuilds the block from the current title, description and breadcrumbs.
Hreflang is generated only for languages that really exist: if a page has no translation, no link to a non-existent address appears. This prevents the "hreflang link leads to 404" error.
- Canonical on every page, domain without www
- Hreflang ru/en/zh/ar + x-default, with no links to missing translations
- Open Graph and Twitter Card with an individual image
- theme-color, favicon set and site.webmanifest
- One script rebuilds the block on all pages at once
03 / structured data
Twelve Schema.org types in one graph on every page
A single Organization + Person graph ties all pages to one site owner, and each page then gets its own type on top — according to what it actually is. Types are chosen automatically by section.
| Schema.org type | Pages | Where it is used |
|---|---|---|
| Organization + Person | 268 + 268 | the whole site — a single owner and author |
| BreadcrumbList | 256 | pages with breadcrumbs, built from the real navigation |
| WebPage | 72 | regular pages |
| Service | 64 | service pages and their subsections |
| CreativeWork | 53 | cases, projects and repositories |
| CollectionPage | 35 | lists: cases, projects, blog, notes |
| Article | 28 | blog posts |
| Book | 8 | "The Craft Bible" and "Color Encyclopedia" in four languages |
| WebSite + SearchAction | 4 | home pages, description of the built-in search |
| ContactPage, SearchResultsPage | 4 + 4 | contacts and search results |
Two deliberate decisions. First: the site has no self-assessed AggregateRating markup — a rating the owner gives themselves is treated by search engines as a violation. Second: I do not rely on FAQ rich snippets — Google discontinued them in May 2026, so the FAQ section is an ordinary page with questions and answers.
04 / headings and metadata
One h1, a unique description and zero duplicates
On 6 September I ran an editorial audit of the texts: removed advertising clichés from the cases, rewrote the intros for naming and brand book, and aligned cards, names and metadata. For search this matters as much as markup: the snippet is built from description and title, and repeated descriptions blur pages against each other.
Width and height on images reserve space before loading — the page does not "jump", which improves the CLS metric. The remaining 11% are dynamic galleries where a script sets the size.
- Title and description are written for the page, not copied from a template
- h2–h3 headings go without skipping levels
- Alt on all images describes the content, not the file name
- Draft and service pages are closed with noindex
05 / indexing
Robots, a 261-URL sitemap and a branded 404
The sitemap is more than a list of addresses: each URL carries links to its versions in other languages, so a search engine gets the map of mirrors in one file. robots.txt points to the sitemap and closes only the /admin/ folder: the site is open to indexing entirely, except the CRM.
When new sections without content appear — for example, pages of future services — they immediately get noindex and stay out of the sitemap. I lift the ban on the day a page is filled in.
- robots.txt: Allow / and Disallow /admin/
- sitemap.xml with hreflang alternates
- 404.html with noindex and links to sections
- Drafts — noindex, follow, no sitemap
- site.webmanifest and a favicon in three formats
06 / host and redirects
One address version and 301 redirects from the old site
The site opens only at https://maksutovdesign.ru: the www version and unsecured http are redirected to the main address with a 301. A search engine does not split weight between four variants of one address.
8 redirect rules from the previous version of the site are kept: old addresses such as /ai-art, /trip, /logofolio and /case/monin lead to the new pages, so external links and bookmarks do not turn into 404s. The server also sends security headers and HSTS for a year.
- www → no www, http → https, both 301
- 8 rules for old addresses
- Directory listing off: Options -Indexes
- HSTS for 1 year and nosniff, SAMEORIGIN headers
07 / speed and weight
Static without frameworks: the home page is 87 KB of HTML
Speed here is a consequence of the architecture, not optimization after the fact: no JS framework, no build step, no heavy CMS. Most of the weight is images, so they are served with a one-year cache lifetime and get a new file name when replaced, so users see the new version immediately. Analytics is my own lightweight counter without third-party cookies; it does not slow the page with someone else's scripts.
08 / internal linking
10,586 internal links and not one broken
I ran every internal link on the site through a check that the target file exists. The check found 4 broken links: the "Download PDF" button in the "Color Encyclopedia" in each language led to a file that does not exist under that name. The links are fixed, and a repeat check shows zero errors.
Breadcrumbs are placed both at the top and the bottom of a page, and they also form the BreadcrumbList markup. The built-in search has four indexes by language — from 437 to 446 entries, with anchors to sections inside long pages: notes, the project archive and book chapters are found by any word.
- Check of all internal links: 0 broken
- Breadcrumbs at the top and bottom
- Anchors to sections inside long pages
- Full-text search across four languages
- Quick-link cards between related sections
09 / how it is maintained
Three scripts and a check before every release
The SEO layer does not go stale because it is not edited by hand. After any content change the same set of actions is run.
| Step | What it does | When it runs |
|---|---|---|
| seopack.py | rebuilds canonical, hreflang, OG and JSON-LD on all pages | after changing a title, description or breadcrumbs |
| build_search_index.py | updates four search indexes from the full page text | after changing text or adding a page |
| Tag check | looks for unclosed and extra tags in every page | before building the release archive |
| Link and mobile layout check | looks for broken links, horizontal scroll and console errors | after major structural changes |
Discuss a project
Need SEO for your website?
Send the site address — I will run an audit, prepare a brief for the fixes and show what to fix first.
Order SEO10 / related pages